初识CFRunLoop

概念

一个线程,用来执行一个任务,执行完成后线程就会退出,然而线程的创建和消耗很耗费资源。所以我们需要一个机制,让线程没有任务执行的时候进入睡眠状态,避免资源占用,需要处理任务时线程被唤醒执行任务。通常的代码逻辑是这样的:

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

系统默认注册了5个Mode:

kCFRunLoopDefaultMode: App平时所处的状态。

UITrackingRunLoopMode: 追踪ScrollView滑动时所处的状态。保证界面滑动时不受其他mode影响。

UIInitializationRunLoopMode:刚启动APP时进入的第一个mode,完成启动时不再使用。

GSEventReceiveRunLoopMode: 接受系统事件的内部mode,同常使用不到。

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/

 

posted @ 2016-01-25 10:15  LaiSong  阅读(202)  评论(0编辑  收藏  举报