NSTimer的简单介绍

我们使用 NSTimer 来创建 timer 对象。一个 timer 对象等待一段时间间隔之后就会触发,发送一个消息给目标对象。例如,我们可以创建一个 timer,发送一个消息给窗口,告诉窗口在某一段时间之后刷新自己。

timer 要结合 runloop (下面又 runloop 简介)一起工作。特别要指出的是,当把 timers 加入 runloop,runloop 会对 timers 保持强引用。

timer 并不是实时的机制。只有当 timer 加入了runloop某一个模式,这个模式在运行而且能够检测到 timers 的触发时间已经过去。因为一个典型的 runloop 管理者各种输入资源,所以有效的事件间隔误差是 50-100ms 之间。如果 timer 的触发时间刚好在 runloop 处理其它事件的时候或者 runloop 所在的模式没有检测 timer,那么 timer 不会被触发,只有当下次 runloop 检测到的时候再触发。因此,timer 真实的触发时间就有可能是比期望的触发事件延迟。

runloop 的简介:
运行循环是线程上用于管理异步到达事件的基础设施。上运行循环通过监视一个或者多个事件源来为线程工作。当事件到达的时候,系统会唤醒线程,然后把事件调度到线程的运行循环,运行循环又会把事件调度给已经指定的处理者。如果没有事件出现或者准备被处理,运行循环会把线程置入睡眠。
我们并不需要为每一个线程都启动运行循环,但是如果那样做,会提供更好的用户体验。运行循环能够以最少的资源去保活线程,因为如果无事可做的时候,运行循环会把线程置入睡眠状态,这样也避免了轮询(轮询会浪费 cpu 周期来避免处理器自己进入睡眠)而且节省了能量。
如何配置一个运行循环呢?我们要做的是启动线程,取得运行循环对象的引用,安装事件处理器,然后把处理器告诉运行循环。

  • 更多内容可以查看在线文档。

Repeating Versus Non-Repeating Timers

当创建 timer 的时候可以指定单次或者是重复。non-repeating timer 触发之后会自动使自己无效来防止再次触发。相反地,repeating timer 触发之后会在相同的runloop重新规划自己。

repeating timer 总是基于规划好的触发时间来规划自己,而不是真实的触发时间。例如,一个 timer 规划好在某个特定的时间触发,之后每 5s 触发一次。未来的触发时间总是会 5s 的倍数的,即使真实的触发时间与所规划的不一致。如果触发时间被延迟了很久甚至导致错过了多个触发时间,timer 在这段时间内也只会触发一次;然后 timer 又重新规划自己的触发时间。

Timer Tolerance

在 iOS 7 之后和 OS X v10.9 之后,我们可以为 timer 指定一个误差容忍度。当 timer 触发的时候,系统的这个灵活性(指 timer 的误差容忍度)有助于优化节约能量和提高响应速度。timer 可以在已 规划好的时间 与 其加上容忍度的和 之间的任意一个时间触发。timer 不会在已规划好的时间之前被触发。对于 repeating timer 触发时间的规划是不考虑 tolerance 的,以避免偏移。默认的 tolerance 的值是 0 。系统保留了可以应用一个比 tolenrance 更小的值 而不管 tolerance property的值的权力。

我们可能知道一个最合适的容忍度。但是一个通用的经验法则是将 tolerance 设置为时间间隔的 10% 。 因为即使是一个很小的一个 tolerance 都会对手机电量的使用产生积极的影响。系统有可能会将 tolerance 设置为最大的可能值。

Scheduling Timers in Run Loops

timer 对象一次只能在一个 runloop 中注册,尽管 timer 可以加入到多个 runloop mode 中。下面又三种创建 timer 的方法:

  • 使用 scheduledTimerWithInterval: invocation: repeats:scheduleTimerWithInterval:targetselector:userInfo:repeats:这两个类方法来创建 timer 并 默认加入当前线程默认模式的 run loop 中;
  • 使用timerWithTimeInterval:invocation: repeats:tiemrWithTimeInterval:target:selector:userInfo:repeats:这两个类方法来创建 timer ,但没有默认加入 run loop。创建之后,使用 NSRunloop 实例方法addTimer:forMode:来将其加入相关的 run loop。
  • 分配 timer 和 初始化 timer 使用initWithFireDate: interval: target: selector: userInfo: repeats:,创建之后,使用 NSRunloop 实例方法addTimer:forMode:来将其加入相关的 run loop。

一旦 timer 加入了 run loop,timer 就会在指定的间隔时间触发直到被废弃。而 non-repeating timer 一旦触发,便自动废弃。但是,对于 repeating timer,我们必须手动调用invalidate 方法来废弃它自己。调用这个方法会将 timer 从相应的 run loop 中移除。但是,我们一定要在安装这个 timer 的线程中调用这个方法。使 timer 无效就是废弃了 timer,因此不会再影响 run loop。run loop 随后会 在invalidate方法返回前后的某个时间点移除 timer,包括对 timer 的强引用。timer 一旦被 无效,就不能再被使用。

你可能感兴趣的:(NSTimer的简单介绍)