一、 回顾 添加 Observer 监听 RunLoop 的所有状态
-
添加 Observer 可以监听到 RunLoop 的各种状态
-
kCFRunLoopEntry: 进入 RunLoop 循环
-
kCFRunLoopBeforeTimers: 处理 定时器(Timers)
-
kCFRunLoopBeforeSources: 处理 Sources
-
kCFRunLoopBeforeWaiting: 休眠之前
-
kCFRunLoopAfterWaiting: 被唤醒
-
kCFRunLoopExit: 退出当前 RunLoop
-
一般来说:从当前 RunLoop 切换到 另外一个 RunLoop;
-
它会先退出当前 RunLoop 的模式,在进入新的模式
二、回顾 RunLoop 中 mode 的内部结构
(有个大概印象,面试前巩固下)(了解)
- Sources0
- Sources1
- Timers
- Observers
三、回顾 项目中的 RunLoop
- 在 项目的main.m 中只有一句代码,这句代码就是 RunLoop 的执行代码。
- UIApplicationMain 方法中会创建 RunLoop 对象,会执行一些 RunLoop 的流程。
- 上面图片的代码 执行的大概过程 如图三:
- 重复的(循环的)做一些事情
- 比如:在睡眠中 等待消息,如果有消息了,就会醒过来处理消息。消息处理完毕,接着睡觉。(一直重复)
- 例如:屏幕是黑色的(这是睡眠中),如果有人点击了屏幕。屏幕就会亮起来(这就是处理消息,或者处理点击事件,点击事件是属于Source1)
四、 苹果官方的 RunLoop 运行逻辑图
无非就是进入某一种模式,把模式的 sources0,sources1,Timers,Observers 拿出来执行。
- 解释上边图片中左侧部分的图片
- 左边的 thread 图片是 线程图片。在这个图片中有一个 黄色的循环圈。可以认为这个循环圈就是RunLoop所要做的事情。
- 黄色的圈主要做了:
- handlePort: 处理端口 ( 端口 -> sources1) 可能是别的线程发的一些消息。线程跟线程的交互一般通过端口的形式。
- customSrc:自定义的源(自定义sources)
- mySelector:处理 selector,如
performSelector:onThread:
- timerFired:定时器
- 解释上边图片中右侧部分的图片
- 上边图片中左侧部分的图片中要做的事情是 外界的一些源给的。
五、RunLoop 具体做的事情(掌握)
01、通知Observers:进入Loop
* RunLoop 在进入循环之前,首先会发出一个通知,告诉监听器,要进入 Loop 了。
02、通知Observers:即将处理Timers
03、通知Observers:即将处理Sources
* 比如: Sources0、Sources1
04、处理Blocks
* RunLoop 运行我们添加 一些 block
CFRunLoopPerformBlock("runLoop", "runLoop的模式", ^{ NSLog(@"block 代码块"); })
05、处理Source0(可能会再次处理Blocks)
06、如果存在Source1,就跳转到第8步
07、通知Observers:开始休眠(等待消息唤醒)
* 如果没有 Source1 就代表没有事情做,才会走这步。
08、通知Observers:结束休眠(被某个消息唤醒)
01> 处理Timer
02> 处理GCD Async To Main Queue
03> 处理Source1
04> 谁唤醒的,处理谁。比如 定时器唤醒的,就处理 timer。
09、处理Blocks
10、根据前面的执行结果,决定如何操作
01> 回到第02步
02> 退出Loop
11、通知Observers:退出Loop