美文网首页
使用 GCD 替代 NSTimer

使用 GCD 替代 NSTimer

作者: Heikki_ | 来源:发表于2017-03-31 11:45 被阅读259次

    使用 NSTimer 或者 performSelector 进行延迟操作有以下需要注意的:

    1. 必须保证有一个活跃的runloop。

    performSelector和scheduledTimerWithTimeInterval方法都是基于runloop的。当一个应用启动时,系统会开启一个主线程,并且把主线程的runloop激活,也就是run起来,并且主线程的runloop是不会停止的。所以,当这两个方法在主线程可以被正常调用。但情况往往不是这样的。实际编码中,我们更多的逻辑是放在子线程中执行的。而子线程的runloop是默认关闭的。这时如果不手动激活runloop,performSelector和scheduledTimerWithTimeInterval的调用将是无效的。

    2.NSTimer的创建与撤销必须在同一个线程操作、performSelector的创建与撤销必须在同一个线程操作。
    3.内存管理有潜在泄露的风险

    scheduledTimerWithTimeInterval方法将target设为A对象时,A对象会被这个timer所持有,也就是会被retain一次,timer会被当前的runloop所持有。performSelector:withObject:afterDelay:方法实际上是在当前线程的runloop里帮你创建的一个timer去执行任务,所以和scheduledTimerWithTimeInterval方法一样会retain其调用对象。

    当一个timer被schedule的时候,timer会持有target对象,NSRunLoop对象会持有timer。当invalidate被调用时,NSRunLoop对象会释放对timer的持有,timer会释放对target的持有。除此之外,我们没有途径可以释放timer对target的持有。所以解决内存泄露就必须撤销timer,若不撤销,target对象将永远无法释放。

    若使用dispatch_after,系统会帮我们处理线程级的逻辑,这样也我们更易于享受系统对线程所做的优化。除此之外,我们不用关心runloop的问题。并且调用的对象也不会被强行持有,这样上述的内存问题也不复存在。当然,需要注意block会持有其传入的对象,但这可以通过weakself解决。所以在这种延迟操作方案中,使用dispatch_after更佳。

    dispatch_after有个致命的弱点:dispatch_after一旦执行后,就不能撤销了。而performSelector可以使用cancelPreviousPerformRequestsWithTarget方法撤销,NSTimer也可以调用invalidate进行撤销。(注意:撤销任务与创建timer任务必须在同一个线程,即同一个runloop)

    以下:使用 GCD 替代 NSTimer

    OC 代码如下

        //创建一个 time 并放到队列中
        dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
        //需要强引用否则 time会销毁,无法继续执行
        self.timer = timer;
        //首次执行时间 间隔时间 时间精度
        dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
        dispatch_source_set_event_handler(timer, ^{
            NSLog(@"----");
        });
        //激活 timer
        dispatch_resume(timer);
    

    SWIFT 给我搞懵逼了 如果你知道请告诉我

    参考(copy):http://www.jianshu.com/p/0c050af6c5ee

    相关文章

      网友评论

          本文标题:使用 GCD 替代 NSTimer

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