1.Runloop 和线程的关系?
-
- runloop和线程是一对一的关系,主线程在启动后会自动创建一个runloop,子线程不会,只有开发人员手动获取线程时,runtime才会去创建当前线程的runloop(懒加载)。(用户无法自己创建runloop,自由runtime可以创建runloop)
-
- Runloop 存储在一个全局的可变字典里,线程是 key ,Runloop 是 value。
RunLoop的运行模式
runloop有5种运行模式,但是runloop只能在一个时刻运行一个模式,若要切换模式,必须停止当前模式。
1. [kCFRunLoopDefaultMode]:这是App的默认运行模式,通常主线程是在这个运行模式下运行。它处理各种常规事件,如用户触摸、计时器、网络请求回调等。
2. [UITrackingRunLoopMode]:这种模式用于跟踪用户交互事件,特别是在滚动视图(如[UIScrollView]中,以确保在用户进行滑动操作时能够快速响应,避免卡顿。
3. [kCFRunLoopCommonModes]:这是一个伪模式,不是一个真正的运行模式,主要用于处理多个模式下的回调。
4. [UIInitializationRunLoopMode]:在App刚启动时进入的第一个模式,用于初始化工作,一旦初始化完成就不再使用。
5. [GSEventReceiveRunLoopMode]:用于接收系统内部事件,通常用不到。
RunLoop的几种状态
1. kCFRunLoopEntry:这是RunLoop的初始状态,表示RunLoop即将开始执行。
2. kCFRunLoopBeforeTimers:在这个状态下,RunLoop会检查所有定时器是否需要触发。
3. kCFRunLoopBeforeSources:在这个状态下,RunLoop会检查所有输入源是否需要处理。
4. kCFRunLoopProcessingInputs:在这个状态下,RunLoop会处理所有输入源的事件。
5. kCFRunLoopBeforeWaiting:在这个状态下,RunLoop会检查是否有需要等待的事件或条件。
6. kCFRunLoopAfterWaiting:在这个状态下,RunLoop会处理等待事件或条件后的后续操作。
-
进入 Loop (kCFRunLoopEntry) :
- 当
RunLoop即将进入事件处理循环时,会触发这个状态。 - 在这个状态下,
RunLoop会进行一些初始化操作,并通知所有注册的观察者(CFRunLoopObserverRef)RunLoop已经进入循环。 - 开发者可以在这个状态下设置一些初始状态或执行一些启动前的准备工作。
- 当
-
即将处理 Timer (kCFRunLoopBeforeTimers) :
- 在
RunLoop即将处理定时源(TimerSource)之前,会触发这个状态。 - 在这个状态下,
RunLoop会通知所有注册的观察者即将处理定时器事件。 - 开发者可以在这个状态下做一些定时任务前的准备工作。
- 在
-
即将处理 Source0 (kCFRunLoopBeforeSources) :
- 在
RunLoop即将处理非基于端口的输入源(Source0)之前,会触发这个状态。 Source0通常是应用主动触发的事件,如触摸事件、键盘事件等。- 在这个状态下,
RunLoop会通知所有注册的观察者即将处理Source0事件。
- 在
-
处理 Source0 (Source Handling) :
- 当
RunLoop正在处理非基于端口的输入源(Source0)时,会处于这个状态。 - 在这个状态下,
RunLoop会调用相应的处理函数来处理Source0事件。
- 当
-
即将处理 Source1 (kCFRunLoopBeforeWaiting) :
- 在
RunLoop即将进入休眠状态前,且没有Source0需要处理时,会触发这个状态。 Source1通常是基于端口的输入源,如网络事件、文件描述符事件等。- 在这个状态下,
RunLoop会通知所有注册的观察者即将进入休眠状态。
- 在
-
进入休眠状态 (kCFRunLoopAfterWaiting) :
- 当
RunLoop没有任何事件需要处理时,会进入休眠状态。 - 在这个状态下,
RunLoop会释放 CPU 资源,等待新的事件到来。 - 当有事件发生时,
RunLoop会被唤醒,并继续处理事件。
- 当
-
即将退出 Loop (kCFRunLoopExit) :
- 当
RunLoop即将退出事件处理循环时,会触发这个状态。 - 在这个状态下,
RunLoop会通知所有注册的观察者RunLoop即将退出。 - 开发者可以在这个状态下执行一些清理工作。
- 当
CFRunLoopRef结构体的简化版本
//简化版本
struct __CFRunLoop {
pthread_t _pthread;
CFMutableSetRef _commonModes;//存储的是字符串,记录所有标记为common的mode
CFMutableSetRef _commonModeItems;//存储所有commonMode的item(source、timer、observer)
CFRunLoopModeRef _currentMode;//当前运行的mode
CFMutableSetRef _modes;//存储的是CFRunLoopModeRef对象,不同mode类型,它的mode名字不同
};
这些是CFRunLoop中最主要的几个字段,可以看到每个RunLoop对应一个pthread_t线程结构体。所以CFRunloop和线程是一一对应的关系。同时还包含了几个Mode集合。