RunLoop总结
需要思考问题
为什么程序在使用的时候可以接受用户的触摸事件,不使用的时候什么事件都不发生?
查看一下 main.m
文件,这是程序启动的入口函数。
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
代码调用的时候,主线程也开始运行。文档上说 UIApplicationMain
函数指定了appliacaion的delegate,并且开启了event cycle。那什么是event cycle?
RunLoop
程序的event cycle其实就是RunLoop,RunLoop在程序启动的时候就开启,接受用户的处理事件。
这是官方文档上面的一个图,可以看到RunLoop在线程中循环监听需要处理的事件。能够接收两种不同的事件源
- Input sources(输入源):传递异步事件。
- Timer sources(定时器): 传递同步事件、发生在特定时间或者重复的时间间隔。
RunLoop Mode
-
Default模式:几乎包含了所有输入源,一般情况下使用这个模式
- NSDefaultRunLoopMode (Cocoa)
- kCFRunLoopDefaultMode (Core Foundation)
-
Connection模式
- 处理NSConnection对象相关事件,系统内部使用,用户基本不会使用。
- Modal模式
- 处理modal panels事件
-
Event tracking模式:滑动Scrollview、Tableview的时候就处于这个模式
- UITrackingRunLoopMode(iOS)
- NSEventTrackingRunLoopMode(cocoa)
-
Common模式: 模式的组合,所有的模式下都可以处理
- NSRunLoopCommonModes (Cocoa)
- kCFRunLoopCommonModes (Core Foundation)
RunLoop与线程的关系
每条线程都有唯一的RunLoop对象与之对应,主线程的RunLoop是自动创建并启动的。子线程的RunLoop需要手动创建,并且调用 run
方法启动。 currentRunLoop
是延迟加载的,只创建一次.
[[NSRunLoop currentRunLoop] run];
指定RunLoop运行的模式和过期时间
- (BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate;
使用场景
1、NSTimer
如果在ScrollView里面使用到NSTimer的,需要调用 addTimer:forMode
方法指定model,才能在滚动的时候生效。
NSTimer创建的定时器因为需要指定model运行,在RunLoop中需要处理各种事件,导致NSTimer不精确。可以使用GCD方法来创建,GCD不受RunLoop的Mode影响.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 要搞一个强引用,不然定时器创建出来就挂了
self.timer = timer;
// 延迟3秒开始执行
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC));
// 每隔2秒执行一次
uint64_t interval = (uint64_t)(2.0 * NSEC_PER_SEC);
dispatch_source_set_timer(self.timer, start, interval, 0);
// 要执行的任务
dispatch_source_set_event_handler(self.timer, ^{
NSLog(@"%s",__func__);
});
// 启动定时器
dispatch_resume(self.timer);
// 停止定时器
dispatch_cancel(self.timer);
2、ImageView的加载
图片的加载放在 NSDefaultRunLoopMode
,因为ScrollView的滚动是在 UITrackingRunLoopMode
下运行的。
3、PerformSelector指定执行的模式
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSString *> *)modes;
参考
1、 官方文档
2、 http://www.cnblogs.com/xuebao/p/4643704.html