iOS timer计时器

timer,计时器,就是用来计时的,可以将它和要处理的动作绑定起来,让这个动作在某段时间之后执行,或者周期性地执行。

一、timer的工作原理

timer的工作和run loop密不可分,由于平常我们使用Application Kit和UIKit来新建的app,在app的主线程启动的时候就自动启动了一个runloop,因此在主线程中使用timer感觉不到runloop的存在。如果要在分线程中使用timer,就必须要了解timer和runloop的协同工作原理,自己去新建runloop,让它和timer一起配合工作。
简短概括runloop和timer的工作关系就是,timer只负责计时,timer所绑定的动作,是由runloop来执行的。下面就来详细地讲讲这种关系。
我们知道,runloop运行的时候需要指定运行模式(run loop mode),runloop的运行模式规定了它要监听的事件源,以及事件发生时它要通知的对象。因此可以给runloop定义多种运行模式,runloop运行时,可以同时启用多个运行模式。
一个timer同一时间只可以注册到一个runloop中,但是可以添加到这个runloop的多个运行模式中。(下图表示了这个关系)
图1.  run loop 和 timer 的关系
初始化一个timer,就是给timer绑定一个要执行的动作;登记一个时间段,这个时间段用来告诉runloop,该动作需要在该时间段过去之后执行,或者每隔这个时间段执行一次。
在timer与runloop的协同工作中,timer只负责计时,而runloop负责监视其所启用的运行模式中添加的timer是否已经达到了其初始化时登记的时间,一旦发现某个timer已经到达了这个时间,就会去执行该timer所绑定的动作(这就是所谓的fire the timer)。
由此可以见得,timer所登记的这个时间段并不是动作的绝对执行时间。timer绑定的动作具体在什么时候执行,要看runloop是否在运行,且是否启用了timer所加入的运行模式,还要看runloop正在处理的东西多不多,能不能及时发现timer已经计时完毕。

二、timer的具体使用

1、创建timer

(1)使用当前的runloop来创建一个timer

方法:

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;

参数TimeInterval是timer计时的周期长度,每隔时长TimeInterval,计时器就会清零一次。
这两个方法,完成一系列动作:

  • 创建timer;
  • 将它加入到当前runloop的默认运行模式中;
  • 让timer开始计时。

对于这种方式添加的timer,runloop就会等它的计时时长第一次达到TimeInterval时,才会执行它绑定的动作。

(2)自己新建一个timer,之后将它注册到某个runloop中

方法:

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;

这两个方法可以返回一个timer。

之后要用runloop对象的方法将timer注册到这个runloop对象的某个运行模式中:

-(void)addTimer:(nonnull NSTimer *) forMode:(nonnull NSString *);

这样添加到runloop的timer会立即开始计时。

(3)初始化一个timer,并指明它绑定的动作被执行的时间点

方法:

- (instanceType)initWithFireDate:(nonnull NSDate *) interval:(NSTimeInterval) target:(nonnull id) selector:(nonnull SEL) userInfo:(nullable id) repeats:(BOOL)

这里的fireDate是个时间点,是相对于系统时间的,只要到达了这个时间点,runloop就会去执行timer绑定的动作。所以如果timer是一次性的,都不需要计时,interval这个参数就没有作用了。如果是重复的timer,才需要计时,参数interval才有用。

可以用setFireDate方法来给timer设定动作的执行时间。

2、停止timer

timer需要在runloop的管理下才会有效,停止timer,只要把它从它所在的runloop中清理掉就可以实现。(或者让runloop停止运行)。

(1)对于一次性的timer

一次性的timer都不用考虑这个问题,因为runloop执行完timer绑定的动作就会自动把这个timer从它所在的运行模式中清理掉。

(2)对于周期性的timer

方法:

-(void)invalidate;

对于周期性的timer才需要考虑这个问题。

要停止一个周期性的timer,要获取这个timer对象的引用,在需要清理timer的时候,主动调用该timer对象的invalidate方法即可。

当然,也可以对一次性的timer执行这个方法,在timer的动作被runloop执行之前调用invalidate方法,timer的动作就永远不会被执行了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值