NSTimer不一定精确

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    if(!_timer) {

        _timer = [NSTimer scheduledTimerWithTimeInterval:1.0target:self selector:@selector(logInfo) userInfo:nil repeats:YES];

    }

}

- (void)logInfo {

float count = 0;

    for (int i = 0; i < 1000000000; i++) {

        count += i;

    }

    NSLog(@"timer test");

}

2017-11-1009:40:38.194879+0800QTimer[9749:3330951] timer test

2017-11-1009:40:44.188463+0800QTimer[9749:3330951] timer test

2017-11-1009:40:50.172012+0800QTimer[9749:3330951] timer test

2017-11-1009:40:56.172139+0800QTimer[9749:3330951] timer test

2017-11-1009:41:02.179022+0800QTimer[9749:3330951] timer test

2017-11-1009:41:08.170254+0800QTimer[9749:3330951] timer test

2017-11-1009:41:14.169011+0800QTimer[9749:3330951] timer test

my god ... 计时偏差已经去到了6秒之多,显然是有问题的

原因分析:

定时器被添加在主线程中,由于定时器在一个RunLoop中被检测一次,所以如果在这一次的RunLoop中做了耗时的操作,当前RunLoop持续的时间超过了定时器的间隔时间,那么下一次定时就被延后了。

解决方法:

在子线程中创建timer,在主线程进行定时任务的操作

在子线程中创建timer,在子线程中进行定时任务的操作,需要UI操作时切换回主线程进行操作

2、RunLoop模式的影响

为了验证,我们在当前页面上添加一个tableview,在定时器运行时,我们对tableview进行滑动操作,可以发现,定时器并不会触发下一次的定时任务。

原因分析:

主线程的RunLoop有两种预设的模式,RunLoopDefaultMode和TrackingRunLoopMode。

当定时器被添加到主线程中且无指定模式时,会被默认添加到DefaultMode中,一般情况下定时器会正常触发定时任务。但是当用户进行UI交互操作时(比如滑动tableview),主线程会切换到TrackingRunLoopMode,在此模式下定时器并不会被触发。

解决方法:

添加定时器到主线程的CommonMode中或者子线程中

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

2、CADisplayLink

CADisplayLink是一个频率能达到屏幕刷新率的定时器类。iPhone屏幕刷新频率为60帧/秒,也就是说最小间隔可以达到1/60s。

基本使用:

CADisplayLink * displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(logInfo)];

[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

3、GCD定时器

我们知道,RunLoop是dispatch_source_t实现的timer,所以理论上来说,GCD定时器的精度比NSTimer只高不低。

基本使用:

NSTimeInterval interval = 1.0;

_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));

dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), interval * NSEC_PER_SEC, 0);

dispatch_source_set_event_handler(_timer, ^{

    NSLog(@"GCD timer test");

});

dispatch_resume(_timer);

你可能感兴趣的:(NSTimer不一定精确)