- 运行循环, 程序一直在循环的做一些事情
处理程序的各种事件, 比如用户触摸事件, 定时器事件等
节省CPU资源, 提高程序性能, 有任务的时候执行任务, 没有任务的时候进入休眠 - NSRunloop CFRunloopRef
runloop与线程
- runloop和线程是1对1的关系
子线程刚创建的时候没有runloop对象, 在第一次获取它的时候创建
主线程runloop已经自动创建, 子线程默认没有开启runloop
runloop会在线程结束时销毁
runloop调用流程

// 通知observer 进入Loop
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
// 即将处理timer
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
// 即将处理sources
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
// 处理Source0
sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
// 处理Source1
__CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply))
// 即将休眠
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
__CFRunLoopSetSleeping(rl);
// 从休眠中唤醒
__CFRunLoopUnsetSleeping(rl);
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
// 通知observer 退出Loop
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
- 通知Observers : 进入Loop
- 通知Observers: 即将处理Timer
- 通知Observers: 将处理Source
- 如果有Source0,处理Source0
如果有Source1,处理Source1
这里的意思是指被source1唤醒, source包含timer ,gcd,source1- 通知Observers: 即将进入休眠
- 通知Observers: 从休眠中唤醒
通过Observers: 退出Loop
image.png
{
/// 1. 通知Observers,即将进入RunLoop
/// 此处有Observer会创建AutoreleasePool: _objc_autoreleasePoolPush();
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopEntry);
do {
/// 2. 通知 Observers: 即将触发 Timer 回调。
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeTimers);
/// 3. 通知 Observers: 即将触发 Source (非基于port的,Source0) 回调。
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeSources);
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);
/// 4. 触发 Source0 (非基于port的) 回调。
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(source0);
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);
/// 6. 通知Observers,即将进入休眠
/// 此处有Observer释放并新建AutoreleasePool: _objc_autoreleasePoolPop(); _objc_autoreleasePoolPush();
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopBeforeWaiting);
/// 7. sleep to wait msg.
mach_msg() -> mach_msg_trap();
/// 8. 通知Observers,线程被唤醒
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopAfterWaiting);
/// 9. 如果是被Timer唤醒的,回调Timer
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(timer);
/// 9. 如果是被dispatch唤醒的,执行所有调用 dispatch_async 等方法放入main queue 的 block
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(dispatched_block);
/// 9. 如果如果Runloop是被 Source1 (基于port的) 的事件唤醒了,处理这个事件
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(source1);
} while (...);
/// 10. 通知Observers,即将退出RunLoop
/// 此处有Observer释放AutoreleasePool: _objc_autoreleasePoolPop();
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(kCFRunLoopExit);
}
runloop休眠的实现原理
通过mach_msg()内核api 从用户态切换到内核态, 没有消息就让线程休眠, 有消息就唤醒线程, 又回到用户态处理想处理的事情
source0
- 点击事件
- 触摸事件
source1
- 基于Port的线程间通信
- 系统事件捕捉
observers
- 监听runloop各种状态切换
- UI刷新事件(beforeWaiting)
- AutoreleasePool释放对象(beforeWaiting)
timers
定时器
performSelector:withObject:afterDelay;

CFRunloopModeRef
runloop的运行模式
当前运行的mode, 称之为currentMode
一个runloop会包含1个或多个mode
, 每个mode都会有若干个source0/source1/observer/timer
如果要切换mode, 需要退出当前loop循环, 再重新选择一个mode进入
不同mode
中的 source0,1/observer/timer互相独立, 互不影响
如果mode里没有
任何任务source0,1/observer/timer, runloop会立刻退出
常见的两种Mode
kCFRunLoopDefaultMode(NSDefaultRunLoopMode)
: 为程序的默认Mode, 通常主线程在这个Mode下运行
UITrackingRunLoopMode
: 界面跟踪Mode, 通常用于列表滑动, 保证界面滑动时不受其他Mode影响
CFRunLoopObserverRef

__CFRunLoop
struct __CFRunLoop {
pthread_t _pthread; // 线程
CFMutableSetRef _commonModes; 所有被标记为common的模式会添加到这个modes下
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode; // 当前模式
CFMutableSetRef _modes; // 所有模式
};
__CFRunLoopMode
struct __CFRunLoopMode {
CFStringRef _name; //mode的名字
CFMutableSetRef _sources; //sources0,1
CFMutableSetRef _observers; //监听器
CFMutableSetRef _timers; // 定时器
};
runloop是如何响应用户操作的, 具体流程是什么
- 首先由source1把系统事件捕捉, 然后又会将事件包装成event 放入事件分发队列中,将event分发给source0中去处理
为什么只能在主线程刷新UI
我们所有的UI操作都来自UIKit这个库, 但是我们操作可能是在多线程的情况下操作, 这样就会有读写不同步的问题, 如果单纯都是用加锁的方案,系统的开销就会很大,(CPU资源, 内存, 时间片轮转), 再加上系统事件的处理也都在主线程中, 如果是在子线程刷新你UI, 我们还得同步处理事件的问题, 所以用户操作和UI要在同一个 线程,还是相对最优的方案
网友评论