Run Loops
Run loop并不像 GCD 或者操作队列那样是一种并发机制,因为它并不能并行执行任务。不过在主 dispatch/operation 队列中, run loop 将直接配合任务的执行,它提供了一种异步执行代码的机制。
Run loop 比起操作队列或者 GCD 来说容易使用得多,因为通过 run loop ,你不必处理并发中的复杂情况,就能异步地执行任务。
一个 run loop 总是绑定到某个特定的线程中。main run loop 是与主线程相关的,在每一个 Cocoa 和 CocoaTouch 程序中,这个 main run loop 都扮演了一个核心角色,它负责处理 UI 事件、计时器,以及其它内核相关事件。无论你什么时候设置计时器、使用 NSURLConnection
或者调用 performSelector:withObject:afterDelay:
,其实背后都是
run loop 在处理这些异步任务。
无论何时你使用 run loop 来执行一个方法的时候,都需要记住一点:run loop 可以运行在不同的模式中,每种模式都定义了一组事件,供 run loop 做出响应。这在对应 main run loop 中暂时性的将某个任务优先执行这种任务上是一种聪明的做法。
关于这点,在 iOS 中非常典型的一个示例就是滚动。在进行滚动时,run loop 并不是运行在默认模式中的,因此, run loop 此时并不会响应比如滚动前设置的计时器。一旦滚动停止了,run loop 会回到默认模式,并执行添加到队列中的相关事件。如果在滚动时,希望计时器能被触发,需要将其设为 NSRunLoopCommonModes
的模式,并添加到
run loop 中。
主线程一般来说都已经配置好了 main run loop。然而其他线程默认情况下都没有设置 run loop。你也可以自行为其他线程设置 run loop ,但是一般来说我们很少需要这么做。大多数时间使用 main run loop 会容易得多。如果你需要处理一些很重的工作,但是又不想在主线程里做,你仍然可以在你的代码在 main run loop 中被调用后将工作分配给其他队列。Chris 在他关于常见的后台实践的文章里阐述了一些关于这种模式的很好的例子。
如果你真需要在别的线程中添加一个 run loop ,那么不要忘记在 run loop 中至少添加一个 input source 。如果 run loop 中没有设置好的 input source,那么每次运行这个 run loop ,它都会立即退出。