收藏iOS小筑

iOS开发基础之Runloop

2015-11-17  本文已影响39人  华子小筑

文章内容来自:
深入理解RunLoop
官方文档-Runloop

Runloop概念

Runloop和线程的关系

Runloop组成

Runloop组成
一个runloop中存在多个Mode,每个Mode中存在Source/Observer/Timer ;每次调用 RunLoop 的主函数时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode。如果需要切换 Mode,只能退出runloop,再重新指定一个 Mode 进入。这样做主要是为了分隔开不同组的 Source/Timer/Observer,让其互不影响
CFRunloopSourceRef (事件产生)

CFRunloopTimerRef

CFRunloopTimerRef包含一个时间长度和函数指针,runloop会注册时间,当时间一到就会触发回调函数;

CFRunloopObserverRef

CFRunloopObserverRef包含一个函数指针,它可以监控runloop的状态,一旦状态改变就会触发回调函数;

 typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry         = (1UL << 0), // 即将进入Loop
kCFRunLoopBeforeTimers  = (1UL << 1), // 即将处理 Timer
kCFRunLoopBeforeSources = (1UL << 2), // 即将处理 Source
kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
kCFRunLoopAfterWaiting  = (1UL << 6), // 刚从休眠中唤醒
kCFRunLoopExit          = (1UL << 7), // 即将退出Loop
};  

Source/Timer/Observer 被统称为 mode item,一个 item 可以被同时加入多个 mode。但一个 item 被重复加入同一个 mode 时是不会有效果的。如果一个 mode 中一个 item 都没有,则 RunLoop 会直接退出,不进入循环

Runloop的Mode

CFRunLoopMode 和 CFRunLoop 的结构大致如下:

struct __CFRunLoopMode {
CFStringRef _name;            // Mode Name, 例如 @"kCFRunLoopDefaultMode"
CFMutableSetRef _sources0;    // Set
CFMutableSetRef _sources1;    // Set
CFMutableArrayRef _observers; // Array
CFMutableArrayRef _timers;    // Array
...
};

struct __CFRunLoop {
CFMutableSetRef _commonModes;     // Set
CFMutableSetRef _commonModeItems; // Set<Source/Observer/Timer>
CFRunLoopModeRef _currentMode;    // Current Runloop Mode
CFMutableSetRef _modes;           // Set
...
};   

RunLoop 的内部逻辑

RunLoop 的内部逻辑

当以一种Mode启动runloop时,CFRunLoopRunSpecific函数会根据ModeName找到对应的Mode,判断Mode内部是否存在source/observer/timer,如果存在会调用CFRunloopRun函数,CFRunloopRun内部存在一个while循环,runloop会通知observers将要分别启动timer、source0、source1,一旦启动observers中对应的回调函数将会被调用;runloop会通过mach_msg()函数接收系统消息,当这一切执行完毕,当前runloop就会退出!

AutoreleasePool

一个runloop循环可以理解创建一个AutoreleasePool,在启动和离开时分别触发AutoreleasePool的push和pop函数,在此次循环结束后完成内存的清理工作;

事件响应

事件的分发有一个hit-testing的过程,这样能够找到最终处理时间的控件,进而执行自定义的逻辑!

手势识别

界面更新

关于网络请求

与 Runloop 相关的实例

NSTimer注册的事件不被执行

日常开发中,与 runLoop 接触得最近可能就是通过 NSTimer 了。一个 Timer 一次只能加入到一个 RunLoop 中。我们日常使用的时候,通常就是加入到当前的 runLoop 的 default mode 中,而 ScrollView 在用户滑动时,主线程 RunLoop 会转到 UITrackingRunLoopMode 。而这个时候, Timer 就不会运行。


有如下两种解决方案:
第一种: 设置RunLoop Mode,例如NSTimer,我们指定它运行于 NSRunLoopCommonModes ,这是一个Mode的集合。注册到这个 Mode 下后,无论当前 runLoop 运行哪个 mode ,事件都能得到执行。
第二种: 另一种解决Timer的方法是,我们在另外一个线程执行和处理 Timer 事件,然后在主线程更新UI。

上一篇 下一篇

猜你喜欢

热点阅读