RunLoop的作用

  1. 等待事件发生:使程序一直运行接受用户输入
  2. 计划事件:决定程序在何时应该处理哪些Event
  3. 调用解耦:事件产生方不需要等待事件处理结束再产生下一个事件
  4. 节省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 下进行,不去设置图片,而是当停止的时候,再去设置图片。

1
2
UIImage *downloadedImage = ...;
[self.avatarImageView performSelector:@selector(setImage:) withObject:downloadedImage afterDelay:0 inModes:@[NSDefaultRunLoopMode]];

RunLoop监听:AFNetworking中监听网络请求

使用NSOperation+NSURLConnection并发模型都会面临NSURLConnection下载完成前线程退出导致NSOperation对象接收不到回调的问题。NSURLConnection的delegate方法需要在connection发起的线程runloop中调用,于是AFNetWorking单独起一个global thread,内置一个runloop,所有的connection都由这个runloop发起,回调也是它接收,不占用主线程,也不耗CPU资源。

NSTimer(timer触发)

1
2
3
4
NSTimer *timer = [NSTimer timerWithTimeInterval:60 block:^(NSTimer * _Nonnull timer) {

} repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
  • 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

 评论