美文网首页
NSTimer不一定精确

NSTimer不一定精确

作者: 参天草 | 来源:发表于2018-03-27 16:33 被阅读0次

    - (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不一定精确

          本文链接:https://www.haomeiwen.com/subject/pvjscftx.html