RunLoop 的三个作用:
1、保证程序不退出(比如:程序启动之后执行的 main 函数里是主线程的 RunLoop,自动开启)。
2、负责监听事件(触摸事件、时钟事件、网络事件)。
3、渲染界面。
特点:有事情就去处理,处理完就休眠。
一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个 Source/Timer/Observer。每次调用 RunLoop 的主函数时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode。
Mode:模式。RunLoop 的工作模式有5种(最后两种程序员触碰不到):
1、默认模式:放时钟、网络事件
2、UI模式:优先级最高(触摸事件)
3、通用模式:占位模式(默认模式和UI模式下的事件都会响应)
4、启动模式:程序在启动时存在的一种模式,启动之后就没有了
5、系统内核模式:处理系统内核事件
Source:事件源。事件源有两个分类:一个是Source0(非系统内核事件。只包含了一个回调(函数指针),它并不能主动触发事件);一个是Source1(系统内核事件。包含了一个 mach_port 和一个回调(函数指针), 能主动唤醒 RunLoop 的线程,如:线程通讯。)
Observer:观察者。监听RunLoop的状态,可监听的状态有:
kCFRunLoopEntry = (1UL << 0), // 即将进入Loop
kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理 Timer
kCFRunLoopBeforeSources = (1UL << 2), // 即将处理 Source
kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
kCFRunLoopAfterWaiting = (1UL << 6), // 刚从休眠中唤醒
kCFRunLoopExit = (1UL << 7), // 即将退出Loop
Timer:定时器。
线程和 RunLoop 之间是一一对应的。主线程的RunLoop默认是自动开启的,子线程的RunLoop默认不开启。线程刚创建时并没有 RunLoop,如果你不主动获取,那它一直都不会有。RunLoop 的创建是发生在第一次获取时,RunLoop 的销毁是发生在线程结束时。
主线程和子线程有什么区别?
对于操作系统来讲,没有本质的区别。但iOS系统对待主线程和子线程有区别:为了提高性能,只在主线程上渲染UI,这样就不需要加锁。(子线程上也可以操作UI,但可能会产生意想不到的bug)