深刻浅出 RunLoop(一):初识
深刻浅出 RunLoop(二):数据结构
深刻浅出 RunLoop(三):事件循环机制
深刻浅出 RunLoop(四):RunLoop 与线程
深刻浅出 RunLoop(五):RunLoop 与 NSTimer
iOS - 聊聊 autorelease 和 @autoreleasepool:RunLoop 与 @autoreleasepoolmarkdown
RunLoop
对象的底层就是一个CFRunLoopRef
结构体,它里面存储着:数据结构
RunLoop
与线程是一一对应关系Source0
/Source1
/Timer
/Observer
RunLoop
当前的运行模式RunLoop
全部的 Mode(CFRunLoopModeRef
)模式// CFRunLoop.h typedef struct __CFRunLoop * CFRunLoopRef; // CFRunLoop.c struct __CFRunLoop { pthread_t _pthread; // 与线程一一对应 CFMutableSetRef _commonModes; CFMutableSetRef _commonModeItems; CFRunLoopModeRef _currentMode; CFMutableSetRef _modes; ... }; 复制代码
CFRunLoopModeRef
表明RunLoop
的运行模式;RunLoop
包含若干个 Mode,每一个 Mode 又包含若干个Source0
/Source1
/Timer
/Observer
;RunLoop
启动时只能选择其中一个 Mode,做为 currentMode;Source0
/Source1
/Timer
/Observer
能分隔开来,互不影响;Source0
/Source1
/Timer
/Observer
,RunLoop
会立马退出。// CFRunLoop.h typedef struct __CFRunLoopMode *CFRunLoopModeRef; // CFRunLoop.c struct __CFRunLoopMode { CFStringRef _name; // mode 类型,如:NSDefaultRunLoopMode CFMutableSetRef _sources0; // CFRunLoopSourceRef CFMutableSetRef _sources1; // CFRunLoopSourceRef CFMutableArrayRef _observers; // CFRunLoopObserverRef CFMutableArrayRef _timers; // CFRunLoopTimerRef ... }; 复制代码
ModeName | 描述 |
---|---|
NSDefaultRunLoopMode / KCFRunLoopDefaultMode | 默认模式 |
UITrackingRunLoopMode | 界面追踪模式,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其余 Mode 影响; |
NSRunLoopCommonModes / KCFRunLoopCommonModes | 通用模式(默认包含 KCFRunLoopDefaultMode 和 UITrackingRunLoopMode) 该模式不是实际存在的一种模式,它只是一个特殊的标记,是同步 Source0 /Source1 /Timer /Observer 到多个 Mode 中的技术方案。被标记为通用模式的Source0 /Source1 /Timer /Observer 都会存放到 _commonModeItems 集合中,会同步这些Source0 /Source1 /Timer /Observer 到多个 Mode 中。 |
备注:框架
NSDefaultRunLoopMode
和NSRunLoopCommonModes
属于Foundation
框架;KCFRunLoopDefaultMode
和KCFRunLoopCommonModes
属于Core Foundation
框架;- 前者是对后者的封装,做用相同。
RunLoop
运行在 Mode1 下面的时候,是处理不了 Mode2 的事件的;NSDefaultRunLoopMode
默认模式和UITrackingRunLoopMode
滚动模式,滚动屏幕的时候就会切换到滚动模式,就不用去处理默认模式下的事件了,保证了 UITableView 等的滚动顺畅。RunLoop
中有两个很重要的概念,一个是上面提到的模式
,还有一个就是事件源
。事件源
分为输入源(Input Sources)
和定时器源(Timer Sources)
两种;输入源(Input Sources)
又分为Source0
和Source1
两种,如下__CFRunLoopSource
中的共用体union
中的version0
和version1
就分别对应Source0
和Source1
。// CFRunLoop.h typedef struct __CFRunLoopSource * CFRunLoopSourceRef; // CFRunLoop.m struct __CFRunLoopSource { CFRuntimeBase _base; uint32_t _bits; pthread_mutex_t _lock; CFIndex _order; /* immutable */ CFMutableBagRef _runLoops; union { CFRunLoopSourceContext version0; /* immutable, except invalidation */ CFRunLoopSourceContext1 version1; /* immutable, except invalidation */ } _context; }; 复制代码
Source0 和 Source1 的区别:oop
Input Sources | 区别 |
---|---|
Source0 | 须要手动唤醒线程:添加Source0 到RunLoop 并不会主动唤醒线程,须要手动唤醒)① 触摸事件处理 ② performSelector:onThread: |
Source1 | 具有唤醒线程的能力 ① 基于 Port 的线程间通讯 ② 系统事件捕捉:系统事件捕捉是由 Source1 来处理,而后再交给Source0 处理 |
CFRunloopTimer
和NSTimer
是 toll-free bridged 的,能够相互转换;performSelector:withObject:afterDelay:
方法会建立timer
并添加到RunLoop
中。// CFRunLoop.h typedef struct CF_BRIDGED_MUTABLE_TYPE(NSTimer) __CFRunLoopTimer * CFRunLoopTimerRef; // CFRunLoop.c struct __CFRunLoopTimer { CFRuntimeBase _base; uint16_t _bits; pthread_mutex_t _lock; CFRunLoopRef _runLoop; // 添加该 timer 的 RunLoop CFMutableSetRef _rlModes; // 全部包含该 timer 的 modeName CFAbsoluteTime _nextFireDate; CFTimeInterval _interval; /* immutable 理想时间间隔 */ CFTimeInterval _tolerance; /* mutable 时间误差 */ uint64_t _fireTSR; /* TSR units */ CFIndex _order; /* immutable */ CFRunLoopTimerCallBack _callout; /* immutable 回调入口 */ CFRunLoopTimerContext _context; /* immutable, except invalidation */ }; 复制代码
做用post
CFRunLoopObserverRef
用来监听RunLoop
的 6 种活动状态/* Run Loop Observer Activities */ typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { kCFRunLoopEntry = (1UL << 0), // 即将进入 RunLoop kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理 Timers kCFRunLoopBeforeSources = (1UL << 2), // 即将处理 Sources kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠 kCFRunLoopAfterWaiting = (1UL << 6), // 刚从休眠中唤醒 kCFRunLoopExit = (1UL << 7), // 即将退出 RunLoop kCFRunLoopAllActivities = 0x0FFFFFFFU // 表示以上全部状态 }; 复制代码
定义ui
// CFRunLoop.h typedef struct __CFRunLoopObserver * CFRunLoopObserverRef; // CFRunLoop.c struct __CFRunLoopObserver { CFRuntimeBase _base; pthread_mutex_t _lock; CFRunLoopRef _runLoop; // 添加该 observer 的 RunLoop CFIndex _rlCount; CFOptionFlags _activities; /* immutable 监听的活动状态 */ CFIndex _order; /* immutable */ CFRunLoopObserverCallBack _callout; /* immutable 回调入口 */ CFRunLoopObserverContext _context; /* immutable, except invalidation */ }; 复制代码
CFRunLoopObserverRef
中的_activities
用来保存RunLoop
的活动状态。当RunLoop
的状态发生改变时,经过回调_callout
通知全部监听这个状态的Observer
。spa