1.什么是RunLoop
RunLoop是通过苹果系统内部维护的事件循环(Event Loop)来对事件/消息进行管理的一个对象。没有消息处理时,休眠已避免资源占用,由用户态切换到内核态。有消息需要处理时,立刻被唤醒,由内核态切换到用户态。
2.RunLoop的数据结构
NSRunLoop(Foundation)是CFRunLoop(CoreFoundation)的封装,提供了面向对象的API RunLoop 相关的主要涉及五个类:
- CFRunLoop:RunLoop对象
- CFRunLoopMode:运行模式
- CFRunLoopSource:输入源/事件源
- CFRunLoopTimmer:定时源
- CFRunLoopObserver:观察者
这五类不做过多的介绍,感兴趣的可以自行去API里面看看其主要的作用。
3.RunLoop的实现机制
RunLoop通过mach_msg()函数接收、发送消息。它的本质是调用函数mach_msg_trap(),相当于是一个系统调用,会触发内核状态切换。在用户态调用 mach_msg_trap()时会切换到内核态;内核态中内核实现的mach_msg()函数会完成实际的工作。
大致逻辑为:
1、通知观察者 RunLoop 即将启动。
2、通知观察者即将要处理Timer事件。
3、通知观察者即将要处理source0事件。
4、处理source0事件。
5、如果基于端口的源(Source1)准备好并处于等待状态,进入步骤9。
6、通知观察者线程即将进入休眠状态。
7、将线程置于休眠状态,由用户态切换到内核态,直到下面的任一事件发生才唤醒线程。
- 一个基于 port 的Source1 的事件。
- 一个 Timer 到时间了。
- RunLoop 自身的超时时间到了。
- 被其他调用者手动唤醒。
8、通知观察者线程将被唤醒。
9、处理唤醒时收到的事件。
- 如果用户定义的定时器启动,处理定时器事件并重启RunLoop。进入步骤2。
- 如果输入源启动,传递相应的消息。
- 如果RunLoop被显示唤醒而且时间还没超时,重启RunLoop。进入步骤2
10、通知观察者RunLoop结束。