NSTimer

用法

NSTimer的用法很简单,个人最常用的是下面这个方法。

[NSTimer scheduledTimerWithTimeInterval:0.5f

                                                          target:self

                                                       selector:@selector(test)

                                                       userInfo:nil

                                                        repeats:YES];

问题:为何停止

有一些人会遇到在页面滑动的时候会发现定时器没有执行

看上面代码你会发现并没有把NSTimer添加到NSRunLoop里面,这种情况会默认把NSTimer添加到NSRunLoop上并且设置mode为NSDefaultRunLoopMode。

在页面滑动的时候,NSRunLoop会自动把Mode切换到 UITrackingRunLoopMode,而默认的却是在NSDefaultRunLoopMode上 ,所以这时候的NSTimer是不会执行的。

解决这个问题挺简单,就是我们要把NSTimer添加到NSRunLoop下的NSRunLoopCommonModes模式下,代码如下:

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5f

                                                                                     target:self

                                                                                   selector:@selector(test)

                                                                                   userInfo:nil

                                                                                      repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

这样就会解决NSTimer滚动时的停止问题。

问题:是否精确

首先告诉你答案:不精确

NSTimer不精确的原因有很多种:

其一 就是类似于上边这种情况,没有把NSTimer添加到RunLoop里面,会默认设置模式为NSDefaultRunLoopMode,在页面滚动到时候会改变RunLoop的Mode为UITrackingRunLoopMode,这个时候肯定是不准确的。

其二 NSTimer是依赖于RunLoop来执行的,如果当前线程里面有太多的逻辑处理、或者数据运算,会影响到RunLoop,所以当前线程如果有非常多的事要处理的话NSTimer的精确性会差一点。

解决办法:既然说了是因为当前线程处理非常的的事,会造成NSTimer丢失准确性,那么你就尽可能的让NSTimer所在的线程尽可能的空闲,比如你可以开一个子线程:

dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5f

                                                                                             target:self

                                                                                          selector:@selector(test)

                                                                                          userInfo:nil

                                                                                            repeats:YES];

        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

});

但是现在你想一下,就算NSTimer所在的线程完全空闲,真的就能使得NSTimer完全准确吗?答案是不能。只能做到相对你能达到的最准确的Timer了。造成的原因是因为苹果有设置一个最小容差的属性tolerance,默认是 0 但是就算你设置为0,苹果依然会有权限有一个最小的容差,因为可以优化电量。

所以你只能做到相对精确,但是做不到完全精确。

停止Timer 

NSTimer提供了一个- (void)invalidate方法,用来结束NSTimer的。在这里需要注意一点:NSTimer的开始跟结束必需要放在一个线程里面,如果A线程开始,B线程结束,你猜NSTimer会��结束吗?

还有一种方法就是:

[timer setFireDate:[NSDate distantFuture]];

timer = nil;

先把timer设置触发的时间设置为future(未来,四级都过了吧?),这样就永远不会触发这个定时器,然后nil。(perfect)

其实第二种方法是对应的暂停跟开始Timer:

//开始

[timer setFireDate:[NSDate distantPast]];

//暂停

[timer setFireDate:[NSDate distantFuture]];

以上是个人平时遇到过的问题以及解决办法,如有错误欢迎指正。

你可能感兴趣的:(NSTimer)