NSTimer和Runloop的关系

什么是NSTimer ?

“A timer provides a way to perform a delayed action or a periodic action. The timer waits until a certain time interval has elapsed and then fires, sending a specified message to a specified object. ”

翻译过来就是Timer就是一个能在从现在开始的后面的某一个时刻或者周期性的执行我们指定的方法的对象。

NSTimer怎样保证参数的生命周期

NSTimer可以选择是否重复执行,为了保证NSTimer调用的方法中传递的对象生命周期,NSTimer会对外界传递的对象进行一次retain

如果是一次性调用的NSTimer,会在本次调用完毕之后invalidateNSTimer自身,而NSTimerretain的对象也会被进行一次release。但是如果是多次重复调用的NSTimer,就需要我们自己在某个特定的时刻来invalidateNSTimer,这个invalidate的时刻是根据我们代码情况来自己决定的,否则将会一直存在。

下面的方法我们先创建了一个Object对象,然后添加了一个NSTimer(关于NSTimerRunloop后面再讲),并且进行了一次release,这时Object并没有被释放,而是被NSTimer进行了一次retain,我们通过在Objectdealloc方法中打印就可以知道是否被释放。

在本次NSTimerTimer所调用方法调用完毕之后,NSTimerinvalidate自身,而Object对象也会被释放。

  Object *object = [[Object alloc] init];  
  [NSTimer scheduledTimerWithTimeInterval:5 target:object selector:@selector(timerAction:) userInfo:nil repeats:NO];  
  [object release];

而通过下面这种方式创建的 Timer就不会被 NSTimer自动释放,因为这次调用是重复调用,必须我们显示的进行 invalidateNSTimer才会消失,这时 Object对象也就会释放了。

  Object *object = [[Object alloc] init];  
  [NSTimer scheduledTimerWithTimeInterval:5 target:object selector:@selector(timerAction:) userInfo:nil repeats:YES];  
  [object release];

总结:
如果使用重复的NSTimer一定要有对应的invalidate,否则Timer会一直存在。
NSTimer会对target对象进行一次retain,所以我们要注意target对象的生命周期。

NSTimer的实时性

无论是单次执行的NSTimer还是重复执行的NSTimer都不是准时的,这与当前NSTimer所处的线程有很大的关系,如果NSTimer当前所处的线程正在进行大数据处理(假设为一个大循环),NSTimer本次执行会等到这个大数据处理完毕之后才会继续执行。

这期间有可能会错过很多次NSTimer的循环周期,但是NSTimer并不会将前面错过的执行次数在后面都执行一遍,而是继续执行后面的循环,也就是在一个循环周期内只会执行一次循环。

无论循环延迟的多离谱,循环间隔都不会发生变化,在进行完大数据处理之后,有可能会立即执行一次NSTimer循环,但是后面的循环间隔始终和第一次添加循环时的间隔相同。

NSTimer与Runloop的关系

我们前面做演示的代码创建的NSTimer会默认为我们添加到RunloopNSDefaultRunLoopMode中,而且由于是在主线程中,所以Runloop是开启的,不需要我们手动打开。

在我们进行多线程编程时,所有的Source都需要添加到Runloop中才能生效,对于我们的NSTimer当然也需要添加到Runloop中才能生效。如果一个Runloop中没有任何Source的话,会立即退出的。而主线程的Runloop在程序运行时,系统就已经为我们添加了很多SourceRunloop中,所以主线程的Runloop是一直存在的,我们可以通过打印MainThread中的Runloop来查看所包含的Source

下面的代码就没有添加到Runloop中,所以这个NSTimer永远也不会发生作用,这是一份错误的代码示例。

  Object *object = [[Object alloc] init];  
  NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:1] interval:1 target:object selector:@selector(timerAction:) userInfo:nil repeats:NO];  
  [object release];

NSTimer添加到Runloop中,但是不运行

iOS多线程中,每一个线程都有一个Runloop,但是只有主线程的Runloop默认是打开的,其他子线程也就是我们创建的线程的Runloop默认是关闭的,需要我们手动运行。

我们可以通过[NSRunLoop currentRunLoop]来获得当前线程的Runloop,并且调用[runloop addTimer:timer forMode:NSDefaultRunLoopMode]方法将定时器添加到Runloop中,最后一定不要忘记调用Runlooprun方法将当前Runloop开启,否则NSTimer永远也不会运行。



原文链接:http://www.jianshu.com/p/f9999b5958f8


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值