Runloop总结

深入理解RunLoop
Mac&iOS之多线程
CFRunLoop运用

RunLoop 的概念

  • runloop是一个对象,管理需要处理的事件和消息
    NSRunloop是CGRumLoopRef的封装,提供面向对象API
  • 不可直接创建runloop,只能用CFRunLoopGetMain() 和 CFRunLoopGetCurrent()获取

Runloop 与线程关系

  • 线程和RunLoop一一对应,只能在一线程中获取对应的runloop

RunLoop 对外的接口

  • CFRunLoopRef

  • CFRunLoopModeRef

  • CFRunLoopSourceRef

  • CFRunLoopTimerRef

  • CFRunLoopObserverRef

Runloop总结_第1张图片
0B1C9605-644C-433E-AD84-6A19E979A7DE.png

一个Runloop包含若干个mode
mode里有若干个Source,Timer, Observer

  • CFRunLoopSourceRef 事件产生的地方

  • source0(不能主动触发事件)

  • source1,包含一个match_port和一个回调(函数指针)能主动唤醒runloop

  • CFRunLoopTimerRef
    基于时间的触发器,包括时间长度和一个回调(函数指针)

  • CFRunLoopObserverRef
    每个Observe都包含一个回调(函数指针),当 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,如果一个mode中一个item都没有 将会退出runloop 有待考证

RunLoop 的 Mode

CFRunLoopMode 和 CFRunLoop的结构大致如下

struct __CFRunLoopMode {

    
CFStringRef _name;            
// Mode Name, 例如 @“kCFRunLoopDefaultMode"和
UITrackingRunLoopMode

    
CFMutableSetRef _sources0;    
// Set

    
CFMutableSetRef _sources1;    
// Set

    
CFMutableArrayRef _observers; 
// Array

    
CFMutableArrayRef _timers;    
// Array

    
...

};

 
 
struct __CFRunLoop {

    
CFMutableSetRef _commonModes;     
// Set 被标记为“common”属性的mode讲添加到这里

    
CFMutableSetRef _commonModeItems; 
// Set 每次进入 runlOOP 将这些item里(source,timer,observer)的内容同步到标记为“common”标记的mode里

    
CFRunLoopModeRef _currentMode;    
// Current Runloop Mode

    
CFMutableSetRef _modes;           
// Set

    
...

};

_commonModes:一个mode可以被添加到这里,每次runloop发生变化时,都会讲_commonModeItems(source,timer,observer)的内容同步到这些mode里

应用场景举例:主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。这两个 Mode 都已经被标记为"Common"属性。DefaultMode 是 App 平时所处的状态,TrackingRunLoopMode 是追踪 ScrollView 滑动时的状态。当你创建一个 Timer 并加到 DefaultMode 时,Timer 会得到重复回调,但此时滑动一个TableView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,并且也不会影响到滑动操作。
有时你需要一个 Timer,在两个 Mode 中都能得到回调,一种办法就是将这个 Timer 分别加入这两个 Mode。还有一种方式,就是将 Timer 加入到顶层的 RunLoop 的 "commonModeItems" 中。"commonModeItems" 被 RunLoop 自动更新到所有具有"Common"属性的 Mode 里去。

RunLoop 的内部逻辑##

Runloop总结_第2张图片
C073E2E9-F640-4574-966E-206C81663560.png

实际上 RunLoop 就是这样一个函数,其内部是一个 do-while 循环。当你调用 CFRunLoopRun() 时,线程就会一直停留在这个循环里;直到超时或被手动停止,该函数才会返回。

RunLoop 的底层实现##

你可能感兴趣的:(Runloop总结)