1.Runloop 和线程的关系?
-
一个线程对应一个 Runloop。
-
主线程的默认就有了 Runloop。
-
子线程的 Runloop 以懒加载的形式创建。
-
Runloop 存储在一个全局的可变字典里,线程是 key ,Runloop 是 value。
2.RunLoop的运行模式
-
RunLoop的运行模式共有5种,RunLoop只会运行在一个模式下,要切换模式,就要暂停当前模式,重写启动一个运行模式
- kCFRunLoopDefaultMode, App的默认运行模式,通常主线程是在这个运行模式下运行 - UITrackingRunLoopMode, 跟踪用户交互事件(用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他Mode影响) - kCFRunLoopCommonModes, 伪模式,不是一种真正的运行模式 - UIInitializationRunLoopMode:在刚启动App时第进入的第一个Mode,启动完成后就不再使用 - GSEventReceiveRunLoopMode:接受系统内部事件,通常用不到
3.runloop内部逻辑?
-
实际上 RunLoop 就是这样一个函数,其内部是一个 do-while 循环。当你调用 CFRunLoopRun() 时,线程就会一直停留在这个循环里;直到超时或被手动停止,该函数才会返回。
内部逻辑:
1. 通知 Observer 已经进入了 RunLoop
2. 通知 Observer 即将处理 Timer
3. 通知 Observer 即将处理非基于端口的输入源(即将处理 Source0)
4. 处理那些准备好的非基于端口的输入源(处理 Source0)
5. 如果基于端口的输入源准备就绪并等待处理,请立刻处理该事件。转到第 9 步(处理 Source1)
6. 通知 Observer 线程即将休眠
7. 将线程置于休眠状态,直到发生以下事件之一
* 事件到达基于端口的输入源(port-based input sources)(也就是 Source0)
* Timer 到时间执行
* 外部手动唤醒
* 为 Run