RunLoop 理解
2017-08-01 本文已影响34人
bonoCat
Runloop解析
概述
do{
}while (1)
从字面的意思来看,就是运行循环,没有终点,一直运行。下面先看下大致 runloop 运行模式
从官方图可以看出,在线程开始的时候就开始运行,知道某个时间点。运行的过程中,会有事件插入(port、custom、performSelector)、timer,这个时候runloop会提醒线程去处理相关的事,其他时间,线程处于休眠状态。
相关类
从图中可以看出一个 Runloop 包含多个 Mode
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
有 5 种 mode
KCFRunLoopDefaultMode // 默认 Mode
UITrackingRunLoopMode // 保证页面滑动不受影响
KCFRunLoopCommonModes // 占位 Mode
UIInitializationRunLoopMode // 刚启动时使用
GSEventReceiveRunLoopMode /// 系统事件内部Mode
每种 mode 包含 一组 source、timer、observer
typedef struct __CFRunLoopSource * CFRunLoopSourceRef;
typedef struct __CFRunLoopObserver * CFRunLoopObserverRef;
typedef struct __CFRunLoopTimer * CFRunLoopTimerRef;
看下都有什么作用
CFRunLoopTimerRef
将定时器添加到指定 Mode ,在指定 Mode 下运行
- (void)timer
{
NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate new] interval:1 repeats:YES block:^(NSTimer *timer) {
NSLog(@"执行了%@", timer);
}];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
CFRunLoopSourceRef
事件源:
1.Port-Based Sources 从其他线程或内核发出
2.custom Input Sources 自定义
- perform Selector Sources
可以从函数调用栈来区分source 0 source 1
- source 0 非Port(点击等)
- source 1 基于Port
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 100, 100, 100)];
btn.backgroundColor = [UIColor redColor];
[btn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
栈调用关系.png
从上面可以看出点击,是source 0 事件
还有就是 perform Selector 的使用方式
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSRunLoopMode> *)modes;
就可以指定performSelector在某个Mode下运行
CFRunLoopObserverRef
runloop 状态监控
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), /// 即将进入RunLoop
kCFRunLoopBeforeTimers = (1UL << 1), /// 即将处理 Timer
kCFRunLoopBeforeSources = (1UL << 2), /// 即将处理 Sources
kCFRunLoopBeforeWaiting = (1UL << 5), /// 即将进入休眠
kCFRunLoopAfterWaiting = (1UL << 6), /// 从休眠中唤醒
kCFRunLoopExit = (1UL << 7), /// 即将退出RunLoop
kCFRunLoopAllActivities = 0x0FFFFFFFU /// 活跃中
};
通过对 RunLoop 监控,可以知道线程的状态,比如空闲时处理一些事情
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAfterWaiting, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
});
/* 不能主动创建 RunLoop
CFRunLoopGetMain()
CFRunLoopGetCurrent()
*/
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
逻辑处理
作用
1.保证程序一直运行
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
程序启动的时候,就会启动一个runloop,使得 main 函数不会有返回值。除非用户主动关闭,或者各种崩溃,或超时,也就是为什么我们app崩溃时候回进入 main 函数。
/* Reasons for CFRunLoopRunInMode() to Return */
enum {
kCFRunLoopRunFinished = 1,
kCFRunLoopRunStopped = 2,
kCFRunLoopRunTimedOut = 3,
kCFRunLoopRunHandledSource = 4
};
2.app各种事件处理(滑动、定时器、performSelector)
3.节省cpu资源