zoukankan      html  css  js  c++  java
  • iOS之 NSTimer(一)

    以前没怎么了解过这个NSTimer,其实还是有挺多坑的,今天来总结一下:

    首先我们一起来看这个:

    我在A  -> (push) -> B控制器,然后再B控制器中开启了一个NSTimer。然后我又pop到A

     

    pop到A的时候,定时器还在运行,并且B没有被释放(未调用dealloc)。why?

    这就不得不让我联想到我上篇写到的 “常驻线程”了,莫非NSTimer也是添加到了RunLoop?

    这说明本例中的NSTimer确实是跑在了NSRunLoop中。

    那为什么B没有释放呢?

    Timer对Target进行了强引用。timer没有被释放,那么B就不会被释放了。也就走不到Dealloc了。那么我们就得在B离开的时候,要对timer进行invalidate。

    - (void)viewWillDisappear:(BOOL)animated{
        
        [super viewWillDisappear:animated];
        [_timer invalidate];
    }

     这个时候NSTimer 销毁了。pop到A的时候,有调用B的dealloc。

    ================ NSTimer 与 RunLoop 的关系

    1.什么是NSTimer?

      A timer waits until a certain time interval has elapsed and then fires, sending a specified message to a target object.

      timer是一个能从某时刻或者周期性的给target对象发送一条指定的消息。

      定时器是线程通知自己做某件事的方法,定时器和你的RunLoop的特定的模式相关。如果定时器所在的模式当前未被RunLoop监视,那么定时器将不会开始 直到RunLoop运行在相应的模式下。如果RunLoop不在运行,那定时器也将永远不启动。

    2. NSTimer的生命周期:

    You specify whether a timer is repeating or non-repeating at creation time. A non-repeating timer fires once and then invalidates itself automatically, thereby preventing the timer from firing again. By contrast, a repeating timer fires and then reschedules itself on the same run loop.

    A repeating timer always schedules itself based on the scheduled firing time, as opposed to the actual firing time

      NSTimer 会对外界传递的target进行retain。如果是一次性调用(repeats:NO),会在本次调用之后自身invalidate,并且NSTimer retain的那个target会做一次release。

      但是,如果是多次重复调用,就需要我们自己手动进行invalidate,不然NSTimer一直存在。

      invalidate的方法中有这么一段话:

    You must send this message from the thread on which the timer was installed. If you send this message from another thread, the input source associated with the timer may not be removed from its run loop, which could prevent the thread from exiting properly.

      NSTimer在那个线程创建就要在那个线程停止,否则资源不能正确的释放。

    3. NSTimer的Tolerance(容差),不是实时机制

    无论是单次执行的NSTimer还是重复执行的NSTimer都不是准时的,这与当前NSTimer所处的线程有很大的关系,如果NSTimer当前所处的线程正在进行大数据处理(假设为一个大循环),NSTimer本次执行会等到这个大数据处理完毕之后才会继续执行。
    这期间有可能会错过很多次NSTimer的循环周期,但是NSTimer并不会将前面错过的执行次数在后面都执行一遍,而是继续执行后面的循环,也就是在一个循环周期内只会执行一次循环。
    无论循环延迟的多离谱,循环间隔都不会发生变化,在进行完大数据处理之后,有可能会立即执行一次NSTimer循环,但是后面的循环间隔始终和第一次添加循环时的间隔相同。

      重复工作定时器会基于安排好的时 间而非实际时间调度它自己运行。举个例子,如果定时器被设定在某一特定时间开始 并 5 秒重复一次,那么定时器会在那个特定时间后 5 秒启动,即使在那个特定的触发 时间延迟了。如果定时器被延迟以至于它错过了一个或多个触发时间,那么定时器会 在下一个最近的触发事件启动,而后面会按照触发间隔正常执行 

    4.Timers work in conjunction with run loops

    其实上面的例子中我们使用的是“ create the timer and schedule it  on the current run loop in the default mode”。这个是在主线程中,所以Runloop是开启的,不需要我们手动打开。

    •   上面的Source/Timer/Observer被统称为mode item,一个item可以被同时加入多个mode。但一个item被重复加入同一个mode时是不会有效果的。如果一个mode中一个item都没有,则RunLoop会被直接退出,不进入循环。
    • 一个RunLoop包含若干个Mode,每个Mode又包含活干个Source/Timer/Oberver,每次调用RunLoop的主函数,只能指定其中的一个Mode, 这个Mode被称作CurrentMode。如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入。这样做的目的: 为了分隔不同组的Source/Timeer/Oberver,让其互不影响.
    • 在iOS多线程中,每一个线程都有一个Runloop,但是只有主线程的Runloop默认是打开的,其他子线程也就是我们创建的线程的Runloop默认是关闭的,需要我们手动运行。我们可以通过[NSRunLoop currentRunLoop]来获得当前线程的Runloop,并且调用[runloop addTimer:timer forMode:NSDefaultRunLoopMode]方法将定时器添加到runloop中,最后一定不要忘记调用runloop的run方法将当前runloop开启,否则NSTimer永远也不会运行。

    NSTimer可以创建一个定时源。

     NSRunLoop *myRunLoop = [NSRunLoop currentRunLoop]; 
     NSDate *futureDate = [NSDate dateWithTimeIntervalSinceNow:1.0];
     _timer = [[NSTimer alloc] initWithFireDate:futureDate interval:1 target:self selector:@selector(doSomething) userInfo:nil repeats:YES];
        
     [myRunLoop addTimer:_timer forMode:NSDefaultRunLoopMode];

     5.对于UIScrollView的Timer

    当使用NSTimerscheduledTimerWithTimeInterval方法时。事实上此时Timer会被加入到当前线程的Run Loop中,且模式是默认的NSDefaultRunLoopMode。而如果当前线程就是主线程,也就是UI线程时,某些UI事件,比如UIScrollView的拖动操作,会将Run Loop切换成NSEventTrackingRunLoopMode模式,在这个过程中,默认的NSDefaultRunLoopMode模式中注册的事件是不会被执行的。也就是说,此时使用scheduledTimerWithTimeInterval添加到RunLoop中的Timer就不会执行。

     NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(timer_callback) userInfo:nil repeats:YES];
        //使用NSRunLoopCommonModes模式,把timer加入到当前Run Loop中。
     [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

     

  • 相关阅读:
    Bootstrap 网格系统(Grid System)实例2
    Bootstrap 网格系统(Grid System)实例1
    Bootstrap 网格系统(Grid System)
    Bootstrap CSS概览
    Bootstrap响应式布局(1)
    46、谈谈你对面向对象的理解?
    算法--练习题1
    堆排序----赠品2
    计数排序----赠品1
    45、如何使用python删除一个文件?
  • 原文地址:https://www.cnblogs.com/Ohero/p/4828623.html
Copyright © 2011-2022 走看看