一、相关概念:
- 首先,RunLoop是iOS/OS X开发中非常基础的一个概念,我们先来看一下有关它的概念和实现方法:
正常来说,一个线程一般只能执行一个任务,执行完成后线程就会退出。现在我们需要一个机制,让线程能随时处理事件但不退出,一般逻辑代码是这样的:
function loop() {
initialize();
do {
var message = get_next_message();
process_message(message);
} while (message != quit);
}
- kCFRunLoopDefaultMode: App的默认 Mode,通常主线程是在这个 Mode 下运行的。
- UITrackingRunLoopMode: 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响。
- UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用。
- GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到。
5.NSRunLoopCommonModes: 包含 1 和 2 一般来说包含 UITrackingRunLoopMode 和 NSDefaultRunLoopMode
二、RunLoop的实现
// 底层的实现函数
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled){
// 配置RunLoop的Mode
SetupCFRunLoopMode()
// 通知 Observers 将要进入 Loop
__CFRunLoopDoObservers(kCFRunLoopEntry);
// 通过GCD设置RunLoop的超时时间
SetupThisRunLoopRunTimeoutTimer();
// RunLoop开始处理事件 do while 循环
do {
// 通知 Observers 将执行timer
__CFRunLoopDoObservers(kCFRunLoopBeforeTimers);
// 通知 Observers 将执行Source0
__CFRunLoopDoObservers(kCFRunLoopBeforeSources);
// 执行blocks
__CFRunLoopDoBlocks();
// 执行Source0
__CFRunLoopDoSource0();
// 问 GCD 主线程有没有需要执行的东西
CheckIfExistMessagesInMainDispatchQueue();
// 通知 Observers 将进入睡眠
__CFRunLoopDoObservers(kCFRunLoopBeforeWaiting);
/* 指定 唤醒端口
监听 mach_msg 会停在这里
进入 mach_msg_trap 状态
睡眠中...
*/
var wakeUpPort = SleepAndWaitForWakingUpPorts();
// 接收到 消息 通知Observers RunLoop被唤醒了
__CFRunLoopDoObservers(kCFRunLoopAfterWaiting);
// 处理事件
if (wakeUpPort == timerPort) {
// 唤醒端口是 timerPort 执行timer回调 /* DOES CALLOUT */
__CFRunLoopDoTimers();
} else if (wakeUpPort == mainDispatchQueuePort) {
// 唤醒端口 执行mainQueue里面的调用
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__()
} else {
// 唤醒端口 执行Source1回调
__CFRunLoopDoSource1();
}
// 执行 blocks
__CFRunLoopDoBlocks();
// 当事件处理完了、被强制停止了、超时了、Mode是空的时候就会退出 循环
} while (!stop && isStopped !timeout && !ModeIsEmpty );
// 通知 Observers 将退出Loop
__CFRunLoopDoObservers(kCFRunLoopExit);
}
说明:本文章仅供学习交流使用
网友评论