CFRunLoopRef
RunLoopRef
RunLoop 对象的底层就是一个 CFRunLoopRef结构体,它里面存储着:
_pthread:RunLoop与线程是一一对应关系
_commonModes:存储着NSString对象的集合(Mode的名称)
_commonModelItems:存储着被标记为通用模式的Sourece0 / Source1 / Timer / Observer
_currentMode: RunLoop 当前的运行模式
_modes:存储着RunLoop所有的Mode(CFRunLoopModeRef)模式
typedef struct __CFRunLoop * CFRunLoopRef;
struct __CFRunLoop {
pthread_t _pthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
...
};
CFRunLoopModeRef
CFRunLoopModeRef 代表 RunLoop 的运行模式;
一个RunLoop包含若干个Mode,作为currentMode;
RunLoop启动时只能选择其中一个Model,作为currentModel;
如果需要切换Mode,只能退出当前Loop,再重新选择一个Mode进入,切换模式不会导致程序退出;
不同Model中的Source0 / Source1/ Timer / Observer 能分隔开来,互不影响;
如果Mode里没有任何Source0 / Source1 / Timer / Observer ,RunLoop会立马退出。
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
CFStringRef _name;
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
...
};
RunLoop 的常见模式
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 框架;- 前者是对后者的封装,作用相同。
CFRunLoopModeRef这样设计有什么好处?Runloop为什么会有多个Mode?
Mode做到了屏蔽的效果,当RunLoop运行在Mode1下面的时候,是处理不了Mode2的事件的;
比如NSDefaultRunLoopMode默认模式和UITrackingRunLoopMode滚动模式,滚动屏幕的时候就会切换到滚动模式,就不用去处理默认模式下的事件了,保证了UITableView等的滚动顺畅。
CFRunLoopSourceRef
在RunLoop中有两个很重要的概念,一个是上面提到的模式,还有一个就是事件源。事件源分为输入源(Input Sources)和定时器源(Timer Sources)两种;
输入源(Input Sources)又分为Source0和Source1两种,以下__CFRunLoopSources中的共用体union中的version0和version1就分别对应Source0和Source1。
typedef struct __CFRunLoopSource * CFRunLoopSourceRef;
struct __CFRunLoopSource {
CFRuntimeBase _base;
uint32_t _bits;
pthread_mutex_t _lock;
CFIndex _order;
CFMutableBagRef _runLoops;
union {
CFRunLoopSourceContext version0;
CFRunLoopSourceContext1 version1;
} _context;
};
Source0 和 Source1 的区别:
Input Sources | 区别 |
---|
Source0 | 需要手动唤醒线程:添加Source0到RunLoop并不会主动唤醒线程,需要手动唤醒)① 触摸事件处理② performSelector:onThread: | Source1 | 具备唤醒线程的能力① 基于 Port 的线程间通信② 系统事件捕捉:系统事件捕捉是由Source1来处理,然后再交给Source0处理 |
CFRunLoopTimerRef
CFRunloopTimer 和NSTimer 是 toll-free bridged 的,可以相互转换;performSelector:withObject:afterDelay: 方法会创建timer 并添加到RunLoop 中。
typedef struct CF_BRIDGED_MUTABLE_TYPE(NSTimer) __CFRunLoopTimer * CFRunLoopTimerRef;
struct __CFRunLoopTimer {
CFRuntimeBase _base;
uint16_t _bits;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFMutableSetRef _rlModes;
CFAbsoluteTime _nextFireDate;
CFTimeInterval _interval;
CFTimeInterval _tolerance;
uint64_t _fireTSR;
CFIndex _order;
CFRunLoopTimerCallBack _callout;
CFRunLoopTimerContext _context;
};
CFRunLoopObserverRef
作用
CFRunLoopObserverRef 用来监听RunLoop 的 6 种活动状态
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0),
kCFRunLoopBeforeTimers = (1UL << 1),
kCFRunLoopBeforeSources = (1UL << 2),
kCFRunLoopBeforeWaiting = (1UL << 5),
kCFRunLoopAfterWaiting = (1UL << 6),
kCFRunLoopExit = (1UL << 7),
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
- UI 刷新(BeforeWaiting)
- Autorelease pool(BeforeWaiting)
定义
typedef struct __CFRunLoopObserver * CFRunLoopObserverRef;
struct __CFRunLoopObserver {
CFRuntimeBase _base;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFIndex _rlCount;
CFOptionFlags _activities;
CFIndex _order;
CFRunLoopObserverCallBack _callout;
CFRunLoopObserverContext _context;
};
CFRunLoopObserverRef 中的_activities 用来保存RunLoop 的活动状态。当RunLoop 的状态发生改变时,通过回调_callout 通知所有监听这个状态的Observer 。
|