iOS-RunLoop
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对象相关事件,系统内部使用,用户基本不会使用。 </ul> </li>
- Modal模式
- 处理modal panels事件 </ul> </li>
-
Event tracking模式:滑动Scrollview、Tableview的时候就处于这个模式
- UITrackingRunLoopMode(iOS)
- NSEventTrackingRunLoopMode(cocoa) </ul> </li>
-
Common模式: 模式的组合,所有的模式下都可以处理
- NSRunLoopCommonModes (Cocoa)
- kCFRunLoopCommonModes (Core Foundation) </ul> </li> </ul>
RunLoop与线程的关系
每条线程都有唯一的RunLoop对象与之对应,主线程的RunLoop是自动创建并启动的。子线程的RunLoop需要手动创建,并且调用 run 方法启动。 currentRunLoop 是延迟加载的,只创建一次.
</div>[[NSRunLoop currentRunLoop] run];
指定RunLoop运行的模式和过期时间
</div>- (BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate;
使用场景
1、NSTimer
如果在ScrollView里面使用到NSTimer的,需要调用 addTimer:forMode 方法指定model,才能在滚动的时候生效。
NSTimer创建的定时器因为需要指定model运行,在RunLoop中需要处理各种事件,导致NSTimer不精确。可以使用GCD方法来创建,GCD不受RunLoop的Mode影响.
</div>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指定执行的模式
</div>- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSString *> *)modes;
参考
1、 官方文档
</div>