RunLoop基础
RunLoop是让线程能随时处理事件但不退出的机制。RunLoop 实际上是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行Event Loop 的逻辑。线程执行了这个函数后,就会一直处于这个函数内部 “接受消息->等待->处理” 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。让线程在没有处理消息时休眠以避免资源占用、在有消息到来时立刻被唤醒。
在主线程中,Main RunLoop
直接配合任务的执行,负责处理UI时间、定时器以及其他相关时间。当自己启动一个线程,如果只是用于处理单一的事件,则该线程在执行完之后就退出了。所以当我们需要让该线程监听某项事务时,就得让线程一直不退出,RunLoop就是这么一个循环,没有事件源的时候,一直休眠;有事件源进来的时候就处理事件。
特点和作用
- 当有事件发生时,RunLoop会根据具体的事件类型通知应用程序作出响应;
- 当没有事件发生时,RunLoop会进入休眠状态,从而达到省电的目的;
- 当事件再次发生时,RunLoop会被重新唤醒,处理事件,调用解耦,节约了CPU时间。
什么时候使用RunLoop?
当需要和该线程进行交互的时候才会使用RunLoop.比如,在一个单独的线程中需要长久的监测某个事件。
怎么用?
添加事件源:
每一个线程都有其对应的RunLoop,但是默认非主线程的RunLoop是没有运行的,需要为RunLoop添加至少一个事件源,然后去run它。RunLoop接收两种源事件:input sources
和timer sources
。
当RunLoop即将启动或已经启动通知观察者之前,RunLoop还要找到对应的Mode,以及判断Mode里面有没有source/timer/observer,如果没有就会直接返回。
CFRunLoopModeRef
代表RunLoop的运行模式,一个RunLoop包含若干个Mode,每个Mode又包含若干个Source/Timer/Observer;- 每次RunLoop启动时,只能指定其中一个 Mode,这个Mode被称作
CurrentMode
; - 如果需要切换Mode,只能先退出Loop,再重新指定一个Mode进入,每一个Mode都是相互独立的;
[NSRunLoop currentRunLoop];
// 获得当前线程的RunLoop对象。
循环驱动:
RunLoop,是线程进入和被线程用来响应事件以及调用事件处理函数的地方.需要在代码中使用控制语句实现RunLoop的循环,也就是说,需要代码提供while或者for循环来驱动RunLoop.在这个循环中,使用一个RunLoop对象执行接收消息,调用对应的处理函数.
Runloop常见的获取方式
Core Foundation
1 | CFRunLoopGetCurrent(); //获得当前线程的RunLoop对象 |
Foundation
1 | [NSRunLoop currentRunLoop]; //获得当前线程的RunLoop对象 |
常见用法和示例
定时器
1 | NSTimer *timer = [NSTimer timerWithTimeInterval:3.0 target:self selector:@selector(goOn) userInfo:nil repeats:YES]; |
在前面我们讲到有五种模式,其中NSRunLoopCommonModes
不是一种真正的模式,它就是一种标记,表示如果其它四种之一被标记为CommonModes
,就会在该模式下工作。在主线程RunLoop中kCFRunLoopDefaultMode
和 UITrackingRunLoopMode
这两个 Mode 都已经被标记为”Common”属性,所以该代码在这两种模式下都能正常工作。此时你无论怎样拖拽tableview,定时器都会正常工作。
添加事件源启动runloop
1 | //1.给RunLoop对象增加一个port,相当于增加一个Source,看到这如果你对AFNetworking有一定的了解的话,你会发现该作者就是这样干的 |