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: target:self selector:@selector(doSomething) userInfo:nil repeats:YES]; [myRunLoop addTimer:_timer forMode:NSDefaultRunLoopMode];
5.对于UIScrollView的Timer
当使用NSTimer的scheduledTimerWithTimeInterval方法时。事实上此时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(一)的更多相关文章
- iOS定时器-- NSTimer 和CADisplaylink
iOS定时器-- NSTimer 和CADisplaylink 一.iOS中有两种不同的定时器: 1. NSTimer(时间间隔可以任意设定,最小0.1ms)// If seconds is les ...
- iOS - OC NSTimer 定时器
前言 @interface NSTimer : NSObject 作用 在指定的时间执行指定的任务. 每隔一段时间执行指定的任务. 1.定时器的创建 当定时器创建完(不用 scheduled 的,添加 ...
- iOS 定时器 NSTimer、CADisplayLink、GCD3种方式的实现
在软件开发过程中,我们常常需要在某个时间后执行某个方法,或者是按照某个周期一直执行某个方法.在这个时候,我们就需要用到定时器. 然而,在iOS中有很多方法完成以上的任务,到底有多少种方法呢?经过查阅资 ...
- iOS 倒计时NSTimer
项目中可能会遇到有些倒计时的地方 比方 手机验证的时候,验证码一般都会有一个时间限制,此时在输入验证码的地方就须要展示一个倒计时 详细实现方式是使用了iOS 自带的 NSTimer 上代码 首先新建 ...
- iOS 里面 NSTimer 防止 循环引用
使用NSTimer的类 #import "TBTimerTestObject.h" #import "TBWeakTimerTarget.h" @interfa ...
- iOS - Swift NSTimer 定时器
前言 public class NSTimer : NSObject 作用 在指定的时间执行指定的任务. 每隔一段时间执行指定的任务. 1.定时器的创建 当定时器创建完(不用 scheduled 的, ...
- iOS定时器NSTimer的使用方法
1.初始化 + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelect ...
- 【转】IOS 计时器 NSTimer
原文网址:http://blog.csdn.net/tangshoulin/article/details/7644124 1.初始化 + (NSTimer *)timerWithTimeInterv ...
- IOS系列——NStimer
Timer经常使用的一些东西 1. 初始化 timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@select ...
随机推荐
- 使用IntelliJ IDEA查看类的继承关系图形
最近正好也没什么可忙的,就回过头来鼓捣过去的知识点,到Servlet部分时,以前学习的时候硬是把从上到下的继承关系和接口实现记得乱七八糟. 这次利用了IDEA的diagram,结果一目了然,也是好用到 ...
- UDP接收百万级数据的解决方案
小序 到新公司不久,就接到一个任务:有个发送方,会通过udp发送一些信息,然后服务接收到信息后保存到数据库的一张表A,保存的这些数据在经过一系列处理,处理完成后累积到另一张表B,然后清空处理的表A的数 ...
- 在0~N个数字中,取指定个数的不重复数字,要求这些数字的和为指定值,求所有结果
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Cons ...
- scoke摘要
登录|注册 关闭 永不磨灭的意志 /* ----------------500G的电影拷到了U盘上,U盘的重量会不会增加?----------------------*/ 目录 ...
- 关于js浮点数计算精度不准确问题的解决办法
今天在计算商品价格的时候再次遇到js浮点数计算出现误差的问题,以前就一直碰到这个问题,都是简单的使用tofixed方法进行处理一下,这对于一个程序员来说是及其不严谨的.因此在网上收集了一些处理浮点数精 ...
- Clojure——学习迷宫生成
背景 初学clojure,想着看一些算法来熟悉clojure语法及相关算法实现. 找到一个各种语言生成迷宫的网站:http://rosettacode.org/wiki/Maze_generation ...
- 认识jQuery的Promise
先前了解了ES6的Promise对象,来看看jQuery中的Promise,也就是jQuery的Deferred对象. 打开浏览器的控制台先. <script> var defer = $ ...
- myeclipse的快捷键
------------------------------------MyEclipse 快捷键1(CTRL)-------------------------------------Ctrl+1 ...
- Prometheus : 入门
Prometheus 是一个开源的监控系统.支持灵活的查询语言(PromQL),采用 http 协议的 pull 模式拉取数据等特点使 Prometheus 即简单易懂又功能强大. Prometheu ...
- Java高级工程师进阶路线
第一部分:宏观方面 一. JAVA.要想成为JAVA(高级)工程师肯定要学习JAVA.一般的程序员或许只需知道一些JAVA的语法结构就可以应付了.但要成为JAVA(高级) 工程师,您要对JAVA做比较 ...