一、认识RunLoop
1.什么是RunLoop?
RunLoop,顾名思义就是运行循环或者跑圈。iOS之所以可以在从后台强制推出前都可以一直运行,就是因为在iOS应用程序的main函数中调用的UIApllicationMain()函数中,创建了一个RunLoop。
2.RunLoop的基本作用
(1).保持程序的持续运行
(2).处理APP中的各种事件(比如触摸事件、定时器事件、selector事件)
(3).节省CPU资源,提高程序性能。(该做事时做事,该休息的时休息)
3.如果没有RunLoop
程序一运行就结束了
int main(int argc, char * argv[]){
NSLog(@"start main function");
return 0; //-->程序在这儿结束
}
4.如果有RunLoop
RunLoop相当于一个无限循环
int main(int argc, char * argv[]) {
BOOL runing = YES; // ---> 程序开始
do{
//执行各种任务,处理各种事件
//.....
}while (runing);
//一直执行do-while循环
return 0;
}
5.iOS main函数中的RunLoop
在第16行代码的UIApplicationMain函数内部就启动了一个RunLoop;所以UIApplicationMain函数就一直没有返回,保持了程序的持续运行。
6、RunLoop对象
1.iOS中有2套API来访问和使用RunLoop
(1).Foundation --> NSRunLoop
(2).core Foundation --> CFRunLoopRef
NSRunLoop和CFRunLoopRef都代表着RunLoop对象
7.RunLoop与线程
(1).每条线程都有唯一的一个与之对应的RunLoop对象
(2).主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建
(3).RunLoop在第一次获取时创建,在线程结束时销毁
(4).相关方法:
a.获取当前线程中的RunLoop对象
//获取当前RunLoop的两种方法
[NSRunLoop currentRunLoop];
CFRunLoopGetCurrent();
这两个方法,在使用的时候,如果当前线程中已经有RunLoop对象,那么会将这个RunLoop对象直接返回。如果当前线程中没有RunLoop对象,那么就会为当前线程创建一个RunLoop对象。
b.获取主线程中的RunLoop对象
//获取主线程中的RunLoop对象
[NSRunLoop mainRunLoop];
CFRunLoopGetMain();
8.RunLoop相关类
Core Foundation 中关于RunLoop的五个类
a.CFRunLoopRef
b.CFRunLoopModelRef
c.CFRunLoopSourceRef
d.CFRunLoopTimerRef
e.CFRunLoopObserverRef
(1)CFRunLoopModeRef
<1>CFRunLoopModeRef代表RunLoop的运行模式
a.一个RunLoop包含若干个Model,每个Model又包含若干个Source/Timer/Observer
b.每次RunLoop启动时,只能指定其中一个Model,这个Mode称作CurrentMode.如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入;这样做主要是为了分割开不同组的Source/Timer/Observer,让其互不影响
<2>系统默认注册了5个Mode
a.kCFRunLoopDefaultMode/NSDefaultRunLoopMode :APP的默认Mode,通常主线程是在这个Mode下运行
b.UITrackingRunLoopMode:界面跟踪Model,用于ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode影响
c.kCFRunLoopCommonModes:这是一个占位用的Mode,不是一种真正的Mode
d.UIInitlizationRunLoopMode:在刚启动App时进入的第一个Mode,启动完成后就不再使用
e.GSEventReceiveRunLoopMode:接收系统事件的内部Mode,通常用不到
//这个代码默认是在主线程的RunLoop中的a.kCFRunLoopDefaultMode模式下执行。当滑动scrollView的时候这个操作不会执行
[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"luffy.jpg"]];
//将显示图片的操作放到标记为NSRunLoopCommonModes的模式下。因为kCFRunLoopDefaultMode和UITrackingRunLoopMode都被标记为NSRunLoopCommonModes。所以不管是滑动还是不滑动scrollView,这个操作都会被执行
[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"luffy.jpg"] afterDelay:3.0f inModes:@[NSRunLoopCommonModes]];
(2)CFRunLoopTimerRef
a.CFRunLoopTimerRef是基于时间的触发器,基本上说的就是NSTimer。
NSTimer * timer = [NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(subThread) userInfo:nil repeats:YES];
//只运行在NSDefaultRunLoopMode模式,一旦RunLoop进入其他模式,这个定时器就不会工作
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
//定时器会跑在标记为common modes的模式下 (默认模式和界面跟踪模式都带有common modes标签)
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
(3)CFRunLoopSourceRef(了解)
<1>.CFRunLoopSourceRef是事件源(输入源)
按照官方文档,source的分类:
a.Port - Based Source
b.Custom InPut Source
c.Cocoa Perform Selector Source
按照函数调用栈,Source的分类:
a.Source0:非基于Port的
b.Source1:基于Port的,通过内核和其他线程通信,接收,分发系统事件
(4)CFRunLoopObserverRef
a.CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变
b.可以监听的时间有以下几个
kCFRunLoopEntry 即将进入Loop //1
kCFRunLoopBeforeTimers 即将处理timer //2
kCFRunLoopBeforeSources 即将处理Source //4
kCFRunLoopBeforeWaiting 即将进入休眠 //32
kCFRunLoopAfterWaiting 刚从休眠中唤醒 //64
kCFRunLoopExit 即将推出Loop //128