iOS之Runloop(3):整理

对Runloop的实际使用进行整理

Posted by Ted on April 16, 2017

其他篇关于Runloop:

iOS之Runloop(1):基础

iOS之Runloop(2):事件源

iOS之Runloop(4):应用

Run loops 是线程相关的的基础框架的一部分。一个 run loop 就是一个事件处理的循环,用来不停的调度工作以及处理输入事件。使用 run loop 的目的是让你的线程在有工作的时候忙于工作,而没工作的时候处于休眠状态。

来源

Run loop 接收输入事件来自两种不同的来源:输入源(input source)和定时源(timer source)。

输入源传递异步事件,通常消息来自于其他线程或程序。

  • 基于端口的输入源:基于端口的输入源由内核自动发送
  • 自定义输入源:自定义的则需要人工从其他线程发送。perforselectoronthread

定时源则传递同步事件,发生在特定时间或者重复的时间间隔。

模式

Run loop 模式是所有要监视的输入源和定时源以及要通知的 runloop注册观察者的集合。每次运行你的 runloop,你都要指定(无论显示还是隐式)其运行个模 式。

在 run loop 运行过程中,只有和模式相关的源才会被监视并允许他们传递事件 消息。(类似的,只有和模式相关的观察者会通知 run loop 的进程)。

其他模式关联的源只有在 run loop 运行在其模式下才会运行,否则处于暂停状态。

  • NSDefaultRunLoopMode: 大多数工作中默认的运行方式。
  • NSConnectionReplyMode: 使用这个Mode去监听NSConnection对象的状态,我们很少需要自己使用这个Mode。
  • NSModalPanelRunLoopMode: 使用这个Mode在Model Panel情况下去区分事件(OS X开发中会遇到)。
  • UITrackingRunLoopMode: 使用这个Mode去跟踪来自用户交互的事件(比如UITableView上下滑动)。
  • GSEventReceiveRunLoopMode: 用来接受系统事件,内部的Run Loop Mode。
  • NSRunLoopCommonModes:这是一个伪模式,其为一组run loop mode的集合。如果将Input source加入此模式,意味着关联Input source到Common Modes中包含的所有模式下。在iOS系统中NSRunLoopCommonMode包含NSDefaultRunLoopMode、NSTaskDeathCheckMode、UITrackingRunLoopMode.可使用CFRunLoopAddCommonMode方法向Common Modes中添加自定义mode。

观察者

run loops 也会生成关于 run loop 行为的通知(notifications)。注册的 run loop 观察者(run-loop Observers)可以收到这些通知,并在线程上面使用它们来做额外的处理。

Run Loop Observer会与以下事件相关联:

  • kCFRunLoopEntry – 进入runloop循环
  • kCFRunLoopBeforeTimers — runloop即将处理一个timer
  • kCFRunLoopBeforeSources – runloop即将处理input sources的事件
  • kCFRunLoopBeforeWaiting – runloop即将休眠
  • kCFRunLoopAfterWaiting – runloop已经唤醒,但是唤醒runloop的是事件还没有处理。
  • kCFRunLoopExit – 退出runloop

启用

在你在辅助线程运行 run loop 之前,你必须至少添加一输入源或定时器给它。 如果 run loop 没有任何源需要监视的话,它会在你启动之际立马退出

[runLoop runUntilDate:[NSDate date]];

当当前长时间运行的线程配置 run loop 的时候,最好添加至少一个输入源到 run loop 以接收消息。虽然你可以使用附属的定时器来进入 run loop,但是一旦定时器 触发后,它通常就变为无效了,这会导致 run loop 退出。虽然附加一个循环的定时 器可以让 run loop 运行一个相对较长的周期,但是这也会导致周期性的唤醒线程, 这实际上是轮询(polling)的另一种形式而已。与之相反,输入源会一直等待某事 件发生,在事情导致前它让线程处于休眠状态。

退出

有两种方法可以让 run loop 处理事件之前退出:

  •  给 run loop 设置超时时间
  • 通知 run loop 停止

​ ​

​ ​ ​