美文网首页ios
OC中定时器的三种实现方式

OC中定时器的三种实现方式

作者: Nevermind | 来源:发表于2017-05-30 21:53 被阅读409次

    NSTimer

    NSTimer 常用的两种创建方式

    + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
    + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
    

    第一种方式

    通过 timerWith… 方法创建的 timer ,需要手动添加到 runloop 中,否则不会启动。

    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(show) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    

    第二种方式

    通过 scheduleTimerWith… 方法创建的 timer,会默认被添加到 runloop 的NSDefaultRunLoopMode中,我们可以手动修改 runloop 的模式。

    NSTimer *timer = [NSTimer timerWithTimeInterval:3.0 target:self selector:@selector(show) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    

    timer不准的原因

    模式的改变

    主线程的 runloop 里有两个预置的Mode:NSDefaultRunLoopModeUITrackingRunLoopMode
    当创建一个 timer 并添加到 defaultMode 时,timer会得到重复回调。但此时滑动一个scrollview,RunLoop 会将 mode 切换到 UITrackingRunLoopMode,这时 timer 不会被回调,并且也不会影响到滑动操作。所以会导致NSTimer不准的情况。

    解决方案:
    定时器添加到 runloop 的 NSRunLoopCommonModes模式中,该模式是以上两种模式的组合。

    线程阻塞

    timer 触发时,如果 runloop 在阻塞状态,timer 的触发会推迟到下一个 runloop 周期,导致延迟。

    dispatch_source 实现高精度定时器

    GCD 实现的定时器不受 runloop 模式的影响,使用 dispatch_source 能够实现没有延迟的定时器。

        dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue1);
        self.timer = timer;
        dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
        dispatch_source_set_event_handler(timer, ^{
            NSLog(@"%@",[NSThread currentThread]);
        });
        dispatch_resume(timer);
    

    CADisplayLink

    能保证和屏幕刷新率相同的频率,将特定的内容画到屏幕上。
    CADisplayLink 以特定的模式的添加到 runloop 后,每当屏幕需要刷新时,runloop 就会像 target 发送 selector 消息。所以 displayLink 的时间间隔是和屏幕刷新频率相关联的。

    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(test)];
    [link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    

    相关文章

      网友评论

        本文标题:OC中定时器的三种实现方式

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