美文网首页iOS面试
NSTimer不准问题解决

NSTimer不准问题解决

作者: Bink | 来源:发表于2017-02-27 11:33 被阅读300次

    NSTimer导致误差的原因:

    1、NSTimer加在main runloop中,模式是NSDefaultRunLoopMode,main负责所有主线程事件,例如UI界面的操作,复杂的运算,这样在同一个runloop中timer就会产生阻塞。

    2、模式的改变。主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。

    当你创建一个 Timer 并加到 DefaultMode 时,Timer 会得到重复回调,但此时滑动一个ScrollView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,并且也不会影响到滑动操作。所以就会影响到NSTimer不准的情况。

    PS:DefaultMode 是 App 平时所处的状态,rackingRunLoopMode 是追踪 ScrollView 滑动时的状态。

    解决的方法,

    1、在主线程中进行NSTimer操作,但是将NSTimer实例加到main runloop的特定mode(模式)中。避免被复杂运算操作或者UI界面刷新所干扰。

    self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(showTime) userInfo:nil repeats:YES];

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

    2、在子线程中进行NSTimer的操作,再在主线程中修改UI界面显示操作结果;

    - (void)timerMethod2 {

    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(newThread) object:nil];

    [thread start];

    }

    - (void)newThread

    {

    @autoreleasepool

    {

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

    [[NSRunLoop currentRunLoop] run];

    }

    }

    一开始的时候系统就为我们将主线程的main runloop隐式的启动了。

    在创建线程的时候,可以主动获取当前线程的runloop。每个子线程对应一个runloop

    3.GCD定时器不受RunLoop约束,比NSTimer更加准时

    @interface ViewController ()

    /** 定时器(这里不用带*,因为dispatch_source_t就是个类,内部已经包含了*) */

    @property (nonatomic, strong) dispatch_source_t timer;

    @end

    int count = 0;

    // 获得队列

    dispatch_queue_t queue = dispatch_get_main_queue();

    // 创建一个定时器(dispatch_source_t本质还是个OC对象)

    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

    // 设置定时器的各种属性(几时开始任务,每隔多长时间执行一次)

    // GCD的时间参数,一般是纳秒(1秒 == 10的9次方纳秒)

    // 何时开始执行第一个任务

    // dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC) 比当前时间晚3秒

    dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));

    uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);

    dispatch_source_set_timer(self.timer, start, interval, 0);

    // 设置回调

    dispatch_source_set_event_handler(self.timer, ^{

    NSLog(@"------------%@", [NSThread currentThread]);

    count++;

    if (count == 4) {

    // 取消定时器

    dispatch_cancel(self.timer);

    self.timer = nil;

    }

    });

    // 启动定时器

    dispatch_resume(self.timer);

    相关文章

      网友评论

        本文标题:NSTimer不准问题解决

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