RunLoop的作用
- 等待事件发生:使程序一直运行接受用户输入
- 计划事件:决定程序在何时应该处理哪些Event
- 调用解耦:事件产生方不需要等待事件处理结束再产生下一个事件
- 节省CPU时间:等待事件发生时不需要耗费CPU
参考资料:RunLoop知识树
RunLoop的几种mode
NSDefaultRunLoopMode/kCFRunLoopDefaultMode
default模式,可以用于大多数操作。在大多数时间,应该使用这种模式来启动和设置输入源。
NSEventTrackingRunLoopMode
Cocoa使用这种模式来约束鼠标拖拽或其它用户界面追踪循环的事件。
NSRunLoopCommonModes/kCFRunLoopCommonModes
这是一个通用的模式组,使用这种模式关联输入源,同样会关联这个模式组里面的每一种模式。对于Cocoa应用来说,这个集合包含了 default、modal以及event tracking模式。
NSConnectionReplyMode
NSModalPanelRunLoopMode
RunLoop和线程的关系
一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出。如果我们需要让线程随时处理事件但并不退出,就需要给线程开启RunLoop。
程序不自动退出是因为主线程自动开启了RunLoop。
开启RunLoop的方法:[NSRunLoop currentRunLoop]
获取当前线程的runloop,若不存在系统会创建一个。
RunLoop的应用
scrollView滑动(mode切换保证滑动不卡顿)
当tableview的cell上有需要从网络获取的图片的时候,滚动tableView,异步线程会去加载图片,加载完成后主线程就会设置cell的图片,但是会造成卡顿。可以让设置图片的任务在CFRunLoopDefaultMode下进行,当滚动tableView的时候,RunLoop是在 UITrackingRunLoopMode 下进行,不去设置图片,而是当停止的时候,再去设置图片。
UIImage *downloadedImage = ...; |
RunLoop监听:AFNetworking中监听网络请求
使用NSOperation+NSURLConnection并发模型都会面临NSURLConnection下载完成前线程退出导致NSOperation对象接收不到回调的问题。NSURLConnection的delegate方法需要在connection发起的线程runloop中调用,于是AFNetWorking单独起一个global thread,内置一个runloop,所有的connection都由这个runloop发起,回调也是它接收,不占用主线程,也不耗CPU资源。
NSTimer(timer触发)
NSTimer *timer = [NSTimer timerWithTimeInterval:60 block:^(NSTimer * _Nonnull timer) { |
- UIEvent事件响应和手势识别(source0事件处理 & source1底层硬件触发)
- AutoRelease(observer,runloop一次循环结束或autorelease pool满了的时候释放)
- NSObject(NSDelayPerforming(timer),NSThreadPerformAddition(source0))
- dispatch_get_main_queue()(serve for dispatch main)
- UI界面刷新、CATransition、CAAnimation(observer) CADisplayLink(source1)
- NSURLConnection(source0处理回调 & source1接收Socket消息) AFNetworking(内置全局线程和runloop管理网络请求)
- AsyncDisplayKit