NSTimer应用

在参与项目开发中遇到了NSTimer的应用,虽然我负责的模块内只用到了一小部分,但我觉得还是有必要拿出来好好琢磨一下。

一、概念(来自官方描述)

  官网上最新的定义是“A timer that fires after a certain time interval has elapsed, sending a specified message to a target object.” 也就是经过一定时间间隔后触发,向目标对象发送指定消息的计时器。

  1、概述

  定时器和run loops协同工作。而且run loops保持对定时器的强引用,所以不需要维护添加到run loops后的定时器。同时为了高效使用计时器,必了解run loops如何运行的。

  计时器不是一个实时生效的机制。如果定时器启动时刻正一个很长时间的callout或者run loop处于一个不再检测这个定时的模式,它将不启动直到run loop检测到下一个启动时刻。所以定时器真正开始生效的时间是在程序设定启动之后的一段时间内。

  NSTimer 是“tool-free bridge”模式,在Core Foundation中对应着CFRunLoopTimerRef。(几个专业名词对我来说真的有些陌生,小菜鸡真的还有很多要学习……)

  2、重复和非重复定时器

  在初始化定时器时,你需要明确这个定时器是否重复。 一个非重复的定时器触发一次后自动失效,从而阻止了定时器的再次触发。相反的是一个重复的定时器触发结束后重新把自己放到run loops中,准备下一次启动。重复计时器总是根据预定的触发时间来调度自己,而不是实际的触发时间。例如,如果一个定时器预定在某个特定的时间触发,每5秒之后,预定的触发时间将永远落在原来的5秒时间间隔内,哪怕是实际发射时间被推迟了。如果触发时间被延迟到通过一个或多个预定的触发间隔,则定时器仅在该时间内发射一次;然后触发后定时器被重新调度,为了未来预定下一次触发。

  3、定时器的容差

  在iOS 7 以及之后的版本和macOS 10.9以及之后的版本,你能指定定时器的容差。在定时器触发时,这个灵活性提高了系统的优化能力,以提高功耗和响应能力。定时器可能在任何预定的触发时间和预定加上容差的时间内触发,不会在预定的触发时间前触发。对于重复定时器,下一个触发时间是从初始的触发时间计算出来的,不管在单个触发时间内的容差,以免漂移。默认值是0,则意味着不使用额外的的容差。系统保留对部分定时器应用少量容差的权利,而不管容差的特性。

  作为定时器的使用者,你能决定定时器的适当容差。一条普遍的规则,将对至少10%的区间的容差设置为重复定时器。即使是少量的容错也会对应用程序的效率产生显著的积极影响。系统能强制执行容差的最大值。

  4、在Run Loops里安置定时器

  你能在一个唯一的run loops中注册一个定时器,尽管它可以被添加到run loops中的多个run loops模式中。这有三种新建定时器的方法:

  ·用方法 scheduledTimerWithTimeInterval:invocation:repeats: 或者
scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: 类方法来创建定时器,并在默认模式下被安置到当前的run loop上。

  ·用方法timerWithTimeInterval:invocation:repeats:  或者 timerWithTimeInterval:target:selector:userInfo:repeats:类方法来创建定时器对象,且无需在run loops上调度它。(创建后,必须手动安置到一个run loop里,通过调用NSRunLoop的函数 addTimer:forMode: )

  ·开辟资源并初始化定时器用 initWithFireDate:interval:target:selector:userInfo:repeats:方法。(同样,你必须手动安置到一个run loop里通过调用NSRunLoop的函数 addTimer:forMode: )

  一旦在run loops上调度,定时器就在指定的的间隔中触发,直到它失效为止。非重复的定时器在触发结束后立刻无效。但对于重复定时器,必须通过调用它的无效方法来使定时器对象无效。调用这个方法要求从当前的run loops中删除定时器,因此你应该在安装定时器的同一线程中调用无效方法。无效的定时器立即禁用为了不让它再影响run loop。之后run loop将删除定时器(以及对应的强引用),或者在还原方法返回前或稍后的某个时间点。一旦失效,定时器对象将不能被重用。

  在重复定时器触发后,它将调度最近间隔的的下一个触发,即在最后一次预定的触发时间内,在指定的容差范围内,定时器间隔的整倍数。如果调用执行选择器或者调用时间长于指定的间隔,则定时器只安排下一次触发。那是定时器为不试图弥补错过触发在调用指定的选择器或调用发生。

  5、子类注意事项

  不要尝试用NSTimer生成子类。

二、实例操作

  我应用到NSTimer的开发部分是为了实现发送验证码状态转换的按钮,实现效果如右动图       

  首先要在设置“发送验证码”按钮时做好接口

[self.sendVerificationCode addTarget:self action:@selector(pressGainCode:) forControlEvents:UIControlEventTouchUpInside];

  配置相关的方法(实例中我取名为pressGainCode),为了支持重复获取验证码的情况,我使用的是重复定时器。

 - (void)pressGainCode:(UIButton *)btn {
[self validationCodeTimer];
} - (void)validationCodeTimer{
__block int timeout = ; //倒计时时间
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, , ,queue);
dispatch_source_set_timer(_timer,dispatch_walltime(NULL, ),1.0*NSEC_PER_SEC, ); //每秒执行
dispatch_source_set_event_handler(_timer, ^{
if(timeout <= ){ //倒计时结束,关闭
dispatch_source_cancel(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
self.sendVerificationCode.userInteractionEnabled = YES;
self.sendVerificationCode.enabled = YES;
[self.sendVerificationCode setTitle:@"重获验证码" forState:UIControlStateNormal];
});
}
else {
timeout--;
NSString *strTime = [NSString stringWithFormat:@"%d秒后重发",timeout];
dispatch_async(dispatch_get_main_queue(), ^{
self.sendVerificationCode.enabled = NO;
[self.sendVerificationCode setTitle:strTime forState:UIControlStateDisabled];
});
}
});
dispatch_resume(_timer);
}

参考资料:Apple官方文档 、四个实用demo 、定时器总结  、官文翻译及基础操作

NSTimer应用的更多相关文章

  1. Objective-C三种定时器CADisplayLink / NSTimer / GCD的使用

    OC中的三种定时器:CADisplayLink.NSTimer.GCD 我们先来看看CADiskplayLink, 点进头文件里面看看, 用注释来说明下 @interface CADisplayLin ...

  2. 解决NSTimer存在的内存泄漏的问题

    创建定时器会在一定的间隔后执行某些操作,一般大家会这样创建定时器,这样创建的定时,self对定时器有个引用,定时器对self也有个引用,造成了循环引用,最终造成了内存泄漏,如果定时器在做下载的操作就会 ...

  3. NSTimer

    NSTimer叫做“定时器”,它的作用如下 在指定的时间执行指定的任务 每隔一段时间执行指定的任务 调用下面的方法就会开启一个定时任务 + (NSTimer *)scheduledTimerWithT ...

  4. NSTimer整理总结

    对于定时器NSTimer,我们大家都不会陌生,在使用的时候,我们常常会遇到一些坑,例如:在Scrollview拖动时,timer会暂停:在子线程中如何创建一个定时器等.针对于一些我们所遇到的坑,我来总 ...

  5. ios - NSTimer中target的self是强引用问题

    当控制器ViewController跳转进入控制器OneViewController中的时候开启定时器,让定时器每隔一段时间打印一次,当OneViewController dismiss的时候,控制器 ...

  6. ios基础篇(二十三)—— 定时器NSTimer与图片的自动切换

    一.NSTimer NSTimer是一个能在从现在开始到后面的某一个时刻或者周期性的执行我们指定的方法的对象.可以按照一定的时间间隔,将制定的信息发送给目标对象.并更新某个对象的行为.你可以选择在未来 ...

  7. NSTimer “定时器”

    •NSTimer叫做“定时器”,它的作用如下 Ø在指定的时间执行指定的任务 Ø每隔一段时间执行指定的任务 Ø •调用下面的方法就会开启一个定时任务 + (NSTimer *)scheduledTime ...

  8. IOS OC 多任务定时器 NSRunLoop 管理 NSTimer

    下面有两种做法 1.使用日期组件 NSDateComponents 2.使用NSString 生成一个日期 //  创建一个日历对象 NSCalendar *calendar = [NSCalenda ...

  9. iOS NSTimer使用详解 开启、关闭、移除

    定时器定时器详解ios定时器关闭定时器NSTimer 一,要使用一个定时器首先要定义一个定时器: @property (strong, nonatomic) NSTimer *myTimer;//定时 ...

  10. NSTimer的使用[zhuang]

    NSTimer 的头文件 /* NSTimer.h Copyright (c) 1994-2015, Apple Inc. All rights reserved. */ #import <Fo ...

随机推荐

  1. easyui 面板title 加东西

  2. git提示错误关于错误:ssh: Could not resolve hostname github.com: Name or service not known.fatal: Could not read from remote repository.

    关于 Git 使用中出现的错误 饥人谷_楠柒 关注 2016.11.02 15:33* 字数 746 阅读 3607评论 5喜欢 10赞赏 1 关于错误:ssh: Could not resolve ...

  3. bootstrap全局样式二

    加form-grope是为了以后更好的管理,一组form写一个form-grope 显示如下: 并排显示的话,给用户名前面再加一个div,再加horizontal,如下,并且加上control-lab ...

  4. ansible 剧本

    ansible的管理与剧本   首先我们安装一个ansible. 在7版本,直接用yum安装就可以 yum -y install ansible 然后清空ansible的配置文件,在里面写入自己需要管 ...

  5. 初次接触Java

    今天初次接触Eclipse,学着用他来建立java工程,话不多说,来看看今天的成果! 熟悉自己手中的开发工具,热热身 刚上手别慌,有问题找度娘 刚刚拿到这个软件的安装包我是一脸懵逼的,因为是从官网下载 ...

  6. 基于MAVEN使用IDEA创建dubbo入门项目图文教程

    花了很长时间没有找到一个很详细的图文教程来学习dubbo入门框架,故记录下来. 一: 项目工程目录 简单介绍项目目录结构: 二: 创建父工程 具体操作步骤: 1,打开IDEA,按下面步骤来 File- ...

  7. CTF资料

    题目大概有这么几个 web,密码学,pwn(综合渗透),misc(杂项),reverse(逆向),ppc(编程类) 入门: http://bobao.360.cn/ctf/  360的CTF训练营ww ...

  8. netty解码器详解(小白也能看懂!)

    什么是编解码器? 首先,我们回顾一下netty的组件设计:Netty的主要组件有Channel.EventLoop.ChannelFuture.ChannelHandler.ChannelPipe等. ...

  9. [Oracle][DATAGUARD] 关于确认PHYSICAL STANDBY的同期状况的方法

    补上简单的确认PHYSICAL STANDBY的同期状况的方法: ODM TEST CASE===================Name = TC#1010_3 ####Primary#### SQ ...

  10. “幕后英雄”之Backing Fields【Microsoft Entity Framework Core随笔】

    刘德华 有一首歌叫<马桶>,其中有一句歌词是:每一个马桶都是英雄. EFCore也有一个英雄,在幕后默默地任劳任怨.它就叫 "支持字段" (Backing Fields ...