1、底层结构
通过看下载源码(下载源码上一篇有介绍),可以看到
struct __CFRunLoop {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* locked for accessing mode list */
__CFPort _wakeUpPort; // used for CFRunLoopWakeUp
Boolean _unused;
volatile _per_run_data *_perRunData; // reset for runs of the run loop
pthread_t _pthread;
uint32_t _winthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
struct _block_item *_blocks_head;
struct _block_item *_blocks_tail;
CFAbsoluteTime _runTime;
CFAbsoluteTime _sleepTime;
CFTypeRef _counterpart;
};
我们稍微简化一下
struct __CFRunLoop {
pthread_t _pthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
};
其中 CFRunLoopModeRef 的结构如下
struct __CFRunLoopMode {
CFStringRef _name;
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
};
图解如下:
2、常见的2中Mode
- kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默认Mode,通常主线程是在这个Mode下运行
- UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode影响
看下Mode里面的4个内容
-
Source0
1、 通过LLDB调试,输入bt , 可以查看函数栈的情况,可以发现触摸事件是由source0处理
2、performSelector:onThread: 也是由source0处理 -
Source1
1、基于Port的线程间通信
2、系统事件的捕捉(例如触摸事件,Source1捕捉,分发给Source0处理) -
Timers
1、NSTimer
2、performSelector:withObject:afterDelay: -
Observers
1、用于监听Runloop的状态
2、UI刷新(BeforeWaiting)
3、Autorelease pool
Runloop的运行逻辑
1.通知Observers:进入Loop
2.通知Observers:即将处理Timers
3.通知Observers:即将处理Sources
4.处理Blocks
5.处理Source0(可能会再次处理Blocks)
6.如果存在Sourc1,就跳转到第8步
7.通知Observers:开始休眠(等待消息唤醒)
8.通知Observers:结束休眠(被某个消息唤醒)
<1>处理Timer
<2>处理GCD Async To Main Queue
<3>处理Source1
9.处理Blocks
10.根据前面的执行结果,决定如何操作
<1>回退到第02步
<2>退出Loop
11.通知Observers:退出Loop
3、Observer的几种状态
查看源码,可以看到
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), // 即将进入Loop
kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理Timers
kCFRunLoopBeforeSources = (1UL << 2), // 即将处理Sources
kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
kCFRunLoopAfterWaiting = (1UL << 6), // 刚刚从休眠中唤醒
kCFRunLoopExit = (1UL << 7), // 即将退出Loop
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
监听方式,通过C语音的API–见下一篇