NSRunloop
1. runloop的定义
RunLoop实际上是一个对象,这个对象在循环中用来处理程序运行过程中出现的各种事件
(比如说触摸事件、UI刷新事件、定时器事件、Selector事件),
从而保持程序的持续运行;而且在没有事件处理的时候,会进入睡眠模式,从而节省CPU资源,提高程序性能。
2. runloop与线程
RunLoop和线程是息息相关的,我们知道线程的作用是用来执行特定的一个或多个任务,但是在默认情况下,线程执行完之后就会退出,就不能再执行任务了。这时我们就需要采用一种方式来让线程能够处理任务,并不退出。所以,我们就有了RunLoop。
一条线程对应一个RunLoop对象,每条线程都有唯一一个与之对应的RunLoop对象。
我们只能在当前线程中操作当前线程的RunLoop,而不能去操作其他线程的RunLoop。
RunLoop对象在第一次获取RunLoop时创建,销毁则是在线程结束的时候。
主线程的RunLoop对象系统自动帮助我们创建好了(原理如下),而子线程的RunLoop对象需要我们主动创建。
3. 默认情况下主线程的RunLoop原理
我们在启动一个iOS程序的时候,系统会调用创建项目时自动生成的main.m的文件。main.m文件如下所示:
int main(int argc, char * argv[]) {
? ? @autoreleasepool {
? ? ? ? return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
? ? }
}
其中UIApplicationMain函数内部帮我们开启了主线程的RunLoop,UIApplicationMain内部拥有一个无线循环的代码。上边的代码中开启RunLoop的过程可以简单的理解为如下代码:
int main(int argc, char * argv[]) {? ? ? ?
? ? BOOL running = YES;
? ? do {
? ? ? ? // 执行各种任务,处理各种事件
? ? ? ? // ......
? ? } while (running);
? ? return 0;
}
从上边可看出,程序一直在do-while循环中执行,所以UIApplicationMain函数一直没有返回,我们在运行程序之后程序不会马上退出,会保持持续运行状态。
下图是苹果官方给出的RunLoop模型图。
官方RunLoop模型图
从上图中可以看出,RunLoop就是线程中的一个循环,RunLoop在循环中会不断检测,通过Input sources(输入源)和Timer sources(定时源)两种来源等待接受事件;然后对接受到的事件通知线程进行处理,并在没有事件的时候进行休息。
4. RunLoop相关类
下面我们来了解一下Core Foundation框架下关于RunLoop的5个类,只有弄懂这几个类的含义,我们才能深入了解RunLoop运行机制。
CFRunLoopRef:代表RunLoop的对象
CFRunLoopModeRef:RunLoop的运行模式
CFRunLoopSourceRef:就是RunLoop模型图中提到的输入源/事件源
CFRunLoopTimerRef:就是RunLoop模型图中提到的定时源
CFRunLoopObserverRef:观察者,能够监听RunLoop的状态改变
CFRunLoopRef就是Core Foundation框架下RunLoop对象类。我们可通过以下方式来获取RunLoop对象:
Core Foundation
CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
CFRunLoopGetMain(); // 获得主线程的RunLoop对象
当然,在Foundation框架下获取RunLoop对象类的方法如下:
Foundation
[NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
[NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
2.2 CFRunLoopModeRef
runloop的五个Mode
系统默认定义了多种运行模式(CFRunLoopModeRef),如下:
kCFRunLoopDefaultMode:App的默认运行模式,通常主线程是在这个运行模式下运行
UITrackingRunLoopMode:跟踪用户交互事件(用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他Mode影响)
UIInitializationRunLoopMode:在刚启动App时第进入的第一个 Mode,启动完成后就不再使用
GSEventReceiveRunLoopMode:接受系统内部事件,通常用不到
kCFRunLoopCommonModes:伪模式,不是一种真正的运行模式(后边会用到)