Runloop:
Runloop是事件接收和分发机制的一个实现;
是线程相关基础框架的一部分;
Runloop的目的:
一个Runloop实质就是一个事件处理的循环:用来不停的调度工作和处理输入事件;
Runloop循环会在有工作的时候工作,没有工作休眠;实际上,他保证了线程结束前不会被终止;
如果没有它,主线程执行完启动任务后,就直接结束了;
Runloop的使用场景:
当需要和线程进行交互的时候才会使用;
Runloop Mode:
前文中我们已经知道,Runloop Mode对应的是一个C语言的结构体:其中主要的是source0、source1、observers、timers;
而Model的不同类型,对应的就是隔绝开来的source、observer、timer的不同组合;
一个Runloop可以有多个Mode,但在某一时刻Runloop只能运行在一个Mode下,处理此Mode中的source、observer和timer;
Model的种类:
前文中我们已经了解过了关于mode的分类;这里,我们只需要知道,不同的mode集合了各自的source、observer和timer;
iOS目前公开的只有NSDefaultRunLoopMode(默认的,正常情况下使用)和NSRunLoopCommonModes,NSRunLoopCommonModes是NSDefaultRunLoopMode和NSEventTrackingRunLoopMode(使用这个Mode来跟踪用户交互事件,比如滑动视图的上下滑动)两者的集合;
Source:
即可以唤醒Runloop的一些事件;比如用户点击屏幕,就会创建一个input source;
·source0:非系统事件;
只包含一个回调(函数指针),不能主动触发事件;
使用时,需要先调用CFRunLoopSourceSignal(source);将这个Source标记为待处理;
然后手动调用CFRunLoopWakeUp(runloop)来唤醒Runloop,让其处理这个事件;
·source1:系统事件:
包含一个mach_port和一个回调(函数指针),被用于通过内核和其他线程相互发送消息;
这种source能主动唤醒Runloop的线程;
Timer:
使用NSTimer API注册执行的任务,就属于这一类;
Observer:
某个Observer可以监听runloop的状态变化,并作出反应;
Runloop的运行流程:
上一节文中已经画出了RunLoop的完整流程;我们在对该图进行注释下;
注解:
一般从mach_port读取msg,只有主线程的Runloop能做,接受到msg立即处理任务;
图中有一句话需要修正:每次loop如果处理完了source0任务,就是说不再有source0任务的处理需要线程等待了,此时poll值为true,timeout值为0(可参考上一篇文章);
下面我们来看下,那些关于Runloop的常见问题:
1.Runloop和线程是什么关系?
每个线程都有唯一的与之对应的Runloop对象,主线程的Runloop自动创建(UIApplicationMain()函数),子线程的Runloop需要主动创建;
Runloop在第一次获取时创建,在线程结束时销毁;
2.Runloop的mode作用?
指定事件在运行循环中的优先级;
线程的运行根据不同的模式,响应不同的事件组合,处理不同的情形;
3.AutoreleasePool和Runloop有什么联系?
NSRunLoop每次循环过程中NSAutoreleasePool对象被生成或废弃;
iOS应用启动后会注册两个 Observer 管理和维护 AutoreleasePool;
应用程序刚刚启动时默认注册了很多个Observer,其中有两个Observer的 callout 都是_wrapRunLoopWithAutoreleasePoolHandler,这两个是和自动释放池相关的两个监听;
·第一个 Observer 会监听 RunLoop 的进入,它会回调objc_autoreleasePoolPush() 向当前的 AutoreleasePoolPage 增加一个哨兵对象标志创建自动释放池。这个 Observer 的 order 是 -2147483647 优先级最高,确保发生在所有回调操作之前;
·第二个 Observer 会监听 RunLoop 的进入休眠和即将退出 RunLoop 两种状态,在即将进入休眠时会调用 objc_autoreleasePoolPop() 和 objc_autoreleasePoolPush() 根据情况从最新加入的对象一直往前清理直到遇到哨兵对象。而在即将退出 RunLoop 时会调用objc_autoreleasePoolPop() 释放自动自动释放池内对象;这个Observer 的 order 是 2147483647 ,优先级最低,确保发生在所有回调操作之后;
4.CFRunLoop和CFRunLoopRef区别?
CFRunLoopRef 基于C 线程安全,NSRunLoop 基于 CFRunLoopRef 面向对象的API 是不安全的;
参考文章: