iOS中有2套API来访问和使用RunLoop
- Foundation:NSRunLoop
- CoreFoundation:CFRunLoopRef
NSRunLoop和CFRunLoopRef都代表着RunLoop对象
-
NSRunLoop是基于CFRunLoopRef的一层OC包装
-
CFRunLoopRef是开源的:
https://opensource.apple.com/tarballs/CF/
Runloop 相关的类
- 主要的成员变量:
struct __CFRunLoop {
pthread_t _pthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
......
};
struct __CFRunLoopMode {
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
......
};
- CFRunLoopRef
- CFRunLoopModeRef:
- CFRunLoopSourceRef
- CFRunLoopTimerRef
- CFRunLoopObserverRef
CFRunLoopModeRef
1. CFRunLoopModeRef
代表RunLoop的运行模式
- 一个RunLoop包含若干个Mode(
CFMutableSetRef _modes;
),每个Mode又包含若干个Source0
/Source1
/Timer
/Observer
; - RunLoop启动时只能选择其中一个Mode,作为
_currentMode
; - 如果需要切换Mode,只能退出当前Loop,再重新选择一个Mode进入;
- 不同组的
Source0
/Source1
/Timer
/Observer
能分隔开来,互不影响。
- 不同组的
- 如果Mode里没有任何
Source0
/Source1
/Timer
/Observer
,RunLoop会立马退出。
2. 常见的2种Mode
-
kCFRunLoopDefaultMode
(NSDefaultRunLoopMode
):App的默认Mode,通常主线程是在这个Mode下运行 -
UITrackingRunLoopMode
:界面跟踪 Mode,用于ScrollView
追踪触摸滑动,保证界面滑动时不受其他 Mode 影响。
Runloop会选择一种模式来运行,那运行时究竟处理什么事呢 ?
- 其实就是处理这四个事务:
Source0
/Source1
/Timer
/Observer
。
1. Source0
- 触摸事件处理
performSelector:onThread:
2. Source1
- 基于Port的线程间通信;
- 系统事件捕捉:
举例:runloop是如何来响应用户操作的 ?- 用户点击屏幕时,source1捕捉系统事件;
- source1将事件包装成事件队列
EventQueue
; - 这个
EventQueue
又是在source0里处理的。
3. Timer
- NSTimer
performSelector:withObject:afterDelay:
4. Observer
- 用于监听RunLoop的状态;
- UI刷新(BeforeWaiting);
- 举例:
self.view.backgroundColor = [UIColor redColor];
这句代码写完之后并不是立即生效,它是等Observer
监听到Runloop即将休眠了,进行UI刷新。
- 举例:
-
Autorelease pool
(BeforeWaiting)。
Observer 监听Runloop的各种状态
// 创建Observer
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
switch (activity) {
case kCFRunLoopEntry:
NSLog(@"kCFRunLoopEntry");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"kCFRunLoopBeforeTimers");
break;
case kCFRunLoopBeforeSources:
NSLog(@"kCFRunLoopBeforeSources");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"kCFRunLoopBeforeWaiting");
break;
case kCFRunLoopAfterWaiting:
NSLog(@"kCFRunLoopAfterWaiting");
break;
case kCFRunLoopExit:
NSLog(@"kCFRunLoopExit");
break;
default:
break;
}
});
// 添加Observer到RunLoop中
CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
// 释放
CFRelease(observer);
网友评论