以前没怎么了解过这个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: 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];

iOS之 NSTimer(一)的更多相关文章

  1. iOS定时器-- NSTimer 和CADisplaylink

    iOS定时器-- NSTimer 和CADisplaylink 一.iOS中有两种不同的定时器: 1.  NSTimer(时间间隔可以任意设定,最小0.1ms)// If seconds is les ...

  2. iOS - OC NSTimer 定时器

    前言 @interface NSTimer : NSObject 作用 在指定的时间执行指定的任务. 每隔一段时间执行指定的任务. 1.定时器的创建 当定时器创建完(不用 scheduled 的,添加 ...

  3. iOS 定时器 NSTimer、CADisplayLink、GCD3种方式的实现

    在软件开发过程中,我们常常需要在某个时间后执行某个方法,或者是按照某个周期一直执行某个方法.在这个时候,我们就需要用到定时器. 然而,在iOS中有很多方法完成以上的任务,到底有多少种方法呢?经过查阅资 ...

  4. iOS 倒计时NSTimer

    项目中可能会遇到有些倒计时的地方 比方 手机验证的时候,验证码一般都会有一个时间限制,此时在输入验证码的地方就须要展示一个倒计时 详细实现方式是使用了iOS 自带的 NSTimer 上代码 首先新建 ...

  5. iOS 里面 NSTimer 防止 循环引用

    使用NSTimer的类 #import "TBTimerTestObject.h" #import "TBWeakTimerTarget.h" @interfa ...

  6. iOS - Swift NSTimer 定时器

    前言 public class NSTimer : NSObject 作用 在指定的时间执行指定的任务. 每隔一段时间执行指定的任务. 1.定时器的创建 当定时器创建完(不用 scheduled 的, ...

  7. iOS定时器NSTimer的使用方法

    1.初始化 + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelect ...

  8. 【转】IOS 计时器 NSTimer

    原文网址:http://blog.csdn.net/tangshoulin/article/details/7644124 1.初始化 + (NSTimer *)timerWithTimeInterv ...

  9. IOS系列——NStimer

    Timer经常使用的一些东西 1. 初始化 timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@select ...

随机推荐

  1. 基于注解方式实现Aop

    开启注解扫描 <context:component-scan base-package="aopSpring"></context:component-scan& ...

  2. S3C2440 时钟设置分析(FCLK, HCLK, PCLK)

    时钟对于一个系统的重要性不言而喻,时钟决定了系统发送数据的快慢,高性能的芯片往往能支持更快速度的时钟,从而提供更好的体验. S3C2440的输入时钟频率是12MHZ,对于这款芯片,显然速度是不够的,所 ...

  3. webstorm配置scss环境

    1.下载 Ruby  (安装过程中记得勾选添加到环境变量,安装结束最后可能会弹出一个cmd弹框,可以忽略) 2. cmd安装sass gem install sass 3. cmd检查是否安装 sas ...

  4. Hive基础(1)---Hive是什么

    1. Hive是什么 Hive是基于Hadoop的数据仓库解决方案.由于Hadoop本身在数据存储和计算方面有很好的可扩展性和高容错性,因此使用Hive构建的数据仓库也秉承了这些特性. 这是来自官方的 ...

  5. 为什么说程序员都应该玩一玩GitHub

    既熟悉又陌生的GitHub 关于GitHub,相信每一个程序员都再熟悉不过了.它为开发者提供Git仓库的托管服务,是全世界最大的代码集中地,被戏称为“全球最大同性交友网站”. 但是对于很大一部分程序员 ...

  6. Python实战之列表简单练习

    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__ ...

  7. ocs的沟通平台

    Microsoft Office Communications Server 2007 R2 简称:OCS准时准确地联系人员以及管理信息过载根据人员的状态与其联系,然后单击最佳方式与其通信:通过电子邮 ...

  8. 如何判断Linux 是32位还是64位

    .运行 'uname -m' 命令 上面的命令内涵太多了,可以用这个参数直指人心:'uname -m' . 例如,在我的系统里,它显示了以下信息: $ uname -m i686

  9. python codis集群客户端(二) - 基于zookeeper对实例创建与摘除

    在这一篇中我们实现了不通过zk来编写codis集群proxys的api,http://www.cnblogs.com/kangoroo/p/7481567.html 如果codis集群暴露zk给你的话 ...

  10. django集成celery之callback方式link_error和on_failure

    在使用django集成celery进行了异步调度任务之后,如果想对失败的任务进行跟踪或者告警,怎么做? 这里提供一个亲测的方法. 1.任务callback 假如你想在任务执行失败的时候,打印错误信息并 ...