概念
一个线程,用来执行一个任务,执行完成后线程就会退出,然而线程的创建和消耗很耗费资源。所以我们需要一个机制,让线程没有任务执行的时候进入睡眠状态,避免资源占用,需要处理任务时线程被唤醒执行任务。通常的代码逻辑是这样的:
function loop() { initialize(); do { var message = get_next_message(); process_message(message); }while (message != quit); }
这种模型被称为Event Loop.比如 Windows 程序的消息循环,比如 OSX/iOS 里的 RunLoop。
所以,RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行上面 Event Loop 的逻辑。线程执行了这个函数后,就会一直处于这个函数内部 "接受消息->等待->处理" 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。
线程与RunLoop的关系
线程与RunLoop之前一一对应。其关系保存在一个字典中,key是phread_t,value是CFRunLoopRef。线程刚创建时是没有RunLoop的,当你第一次获取线程对应的RunLoop时,RunLoop对象被创建。RunLoop的销毁是发生在线程结束时。
RunLoop的mode
kCFRunLoopDefaultMode: App平时所处的状态。
TrackingRunLoopMode: 追踪ScrollView滑动时所处的状态。
kCFRunLoopCommonModes:加入到这个mode中的ource/Observer/Timer ,每当RunLoop发生变化时,RunLoop 都会自动将 _commonModeItems 里的 Source/Observer/Timer 同步到具有 "Common" 标记的所有Mode里。
例子:
问题描述:当我在tableView中使用定时器时,加入一个时间倒计时,每1秒更新时间,但是发现定时器的执行非常不准。
原因:当我们滑动tableView时,RunLoop会切换到TrackingRunLoopMode模式,由于定时器默认是加在DefaultMode模式下,所以在TrackingRunLoopMode下不会执行定时器的响应,定时器事件被阻塞,当滑动结束时切换回DefaultMode,执行定时器之前被阻塞的事件,导致时间倒计时不到1秒就被更新。
解决方法: [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];将定时器加入到RunLoop的CoomonModes下
参考:http://blog.ibireme.com/2015/05/18/runloop/