一、介绍

在iOS中,计时器是比较常用的,用于统计累加数据或者倒计时等,例如手机号获取验证码。计时器大概有那么三种,分别是:NSTimer、CADisplayLink、dispatch_source_t

二、使用

@property (strong,nonatomic)NSTimer *timer;
@property (strong,nonatomic)CADisplayLink *displaylinkTimer;
@property (strong,nonatomic)dispatch_source_t sourceTimer;

1、NSTimer:

//NSTimer
-(void)createTimer{ //初始化
//_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
//执行操作
//}]; _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerStart:) userInfo:nil repeats:YES]; //加入runloop循环池
[[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode]; //开启定时器
[_timer fire];
}
-(void)timerStart:(NSTimer *)timer{
NSLog(@"%s-----%lf",__func__,timer.timeInterval); //销毁定时器
//[_timer invalidate];
//_timer = nil;
}

解释:

  • TimerInterval: 执行之前等待的时间。比如设置成1.0,就代表1秒后执行方法
  • target: 需要执行方法的对象。
  • selector : 需要执行的方法
  • repeats : 是否需要循环

注意 :
调用创建方法后,target对象的计数器会加1,直到执行完毕,自动减1。如果是循环执行的话,就必须手动关闭,否则可以不执行释放方法。

特性:

  • 存在延迟
  • 不管是一次性的还是周期性的timer的实际触发事件的时间,都会与所加入的RunLoop和RunLoop Mode有关,如果此RunLoop正在执行一个连续性的运算,timer就会被延时出发。重复性的timer遇到这种情况,如果延迟超过了一个周期,则会在延时结束后立刻执行,并按照之前指定的周期继续执行。
  • 必须加入Runloop

使用上面的创建方式,会自动把timer加入MainRunloop的NSDefaultRunLoopMode中。如果使用以下方式创建定时器,就必须手动加入Runloop:

NSTimer *timer = [NSTimer timerWithTimeInterval: target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

2、CADisplayLink:

//CADisplayLink
-(void)createCADisplayLink{ _displaylinkTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
[_displaylinkTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
-(void)handleDisplayLink:(CADisplayLink *)displaylinkTimer{
NSLog(@"%s-----%ld",__func__,displaylinkTimer.preferredFramesPerSecond); //销毁定时器
//[_displaylinkTimer invalidate];
//_displaylinkTimer = nil;
}

解释:

当把CADisplayLink对象add到runloop中后,selector就能被周期性调用,类似于重复的NSTimer被启动了;执行invalidate操作时,CADisplayLink对象就会从runloop中移除,selector调用也随即停止,类似于NSTimer的invalidate方法。

特性:

  • 屏幕刷新时调用CADisplayLink是一个能让我们以和屏幕刷新率同步的频率将特定的内容画到屏幕上的定时器类。CADisplayLink以特定模式注册到runloop后,每当屏幕显示内容刷新结束的时候,runloop就会向CADisplayLink指定的target发送一次指定的selector消息, CADisplayLink类对应的selector就会被调用一次。所以通常情况下,按照iOS设备屏幕的刷新率60次/秒
  • 延迟iOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确度相当高。但如果调用的方法比较耗时,超过了屏幕刷新周期,就会导致跳过若干次回调调用机会。如果CPU过于繁忙,无法保证屏幕60次/秒的刷新率,就会导致跳过若干次调用回调方法的机会,跳过次数取决CPU的忙碌程度。

使用场景:

  • 从原理上可以看出,CADisplayLink适合做界面的不停重绘,比如视频播放的时候需要不停地获取下一帧用于界面渲染。

重要属性:

  • frameInterval(已过时,用preferredFramesPerSecond替代)  NSInteger类型的值,用来设置间隔多少帧调用一次selector方法,默认值是1,即每帧都调用一次。
  • duration  readOnly的CFTimeInterval值,表示两次屏幕刷新之间的时间间隔。需要注意的是,该属性在target的selector被首次调用以后才会被赋值。selector的调用间隔时间计算方式是:调用间隔时间 = duration × frameInterval。

3、dispatch_source_t:

//dispatch_source_t
-(void)createDispatch_source_t{ //创建全局队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ); //使用全局队列创建计时器
_sourceTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, , , queue); //定时器延迟时间
NSTimeInterval delayTime = 1.0f; //定时器间隔时间
NSTimeInterval timeInterval = 1.0f; //设置开始时间
dispatch_time_t startDelayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayTime * NSEC_PER_SEC)); //设置计时器
dispatch_source_set_timer(_sourceTimer,startDelayTime,timeInterval*NSEC_PER_SEC,0.1*NSEC_PER_SEC); //执行事件
dispatch_source_set_event_handler(_sourceTimer,^{ //销毁定时器
//dispatch_source_cancel(_myTimer);
}); //启动计时器
dispatch_resume(_sourceTimer);
}

特性:

  • 默认是重复执行的,可以在事件响应回调中通过dispatch_source_cancel方法来设置为只执行一次,如下代码:
dispatch_source_set_event_handler(_timer, ^{
//执行事件
dispatch_source_cancel(_timer);}
);

重要属性:

dispatch_source_set_timer(dispatch_source_t source,
dispatch_time_t start,
uint64_t interval,
uint64_t leeway);
  • start计时器起始时间,可以通过dispatch_time创建,如果使用DISPATCH_TIME_NOW,则创建后立即执行
  • interval计时器间隔时间,可以通过timeInterval * NSEC_PER_SEC来设置,其中,timeInterval为对应的秒数
  • leeway这个参数的理解,我觉得http://www.dreamingwish.com上Seven's同学的解释很直观也很易懂:“这个参数告诉系统我们需要计时器触发的精准程度。所有的计时器都不会保证100%精准,这个参数用来告诉系统你希望系统保证精准的努力程度。如果你希望一个计时器没五秒触发一次,并且越准越好,那么你传递0为参数。另外,如果是一个周期性任务,比如检查email,那么你会希望每十分钟检查一次,但是不用那么精准。所以你可以传入60,告诉系统60秒的误差是可接受的。这样有什么意义呢?简单来说,就是降低资源消耗。如果系统可以让cpu休息足够长的时间,并在每次醒来的时候执行一个任务集合,而不是不断的醒来睡去以执行任务,那么系统会更高效。如果传入一个比较大的leeway给你的计时器,意味着你允许系统拖延你的计时器来将计时器任务与其他任务联合起来一起执行。

优点:

  • 时间准确
  • 可以使用子线程,解决定时间跑在主线程上卡UI问题

注意事项:

  • 需要将dispatch_source_t timer设置为成员变量,不然会立即释放

三、参考原链接:

http://www.jianshu.com/p/53c07eb57223

iOS:三种常见计时器(NSTimer、CADisplayLink、dispatch_source_t)的使用的更多相关文章

  1. iOS开发--计时器-NSTimer与CADisplayLink

    如果程序要让某个方法重复执行,可以借助定时器来完成.CADisplayLink是一个能让我们以和屏幕刷新率相同的频率将内容画到屏幕上的定时器,NSTimer的精确度低了点,比如NSTimer的触发时间 ...

  2. 浅析NSTimer & CADisplayLink内存泄露

    偶得前言 NSRunLoop与定时器 - invalidate的作用 我们如何解决? 偶得前言 本篇文章中我们主要谈谈NSTimer\CADisplayLink在使用过程中牵扯到内存泄露的相关问题及解 ...

  3. 深入学习jQuery的三种常见动画效果

    × 目录 [1]显隐效果 [2]高度变化 [3]淡入淡出 前面的话 动画效果是jQuery吸引人的地方.通过jQuery的动画方法,能够轻松地为网页添加视觉效果,给用户一种全新的体验.jQuery动画 ...

  4. Android应用开发中三种常见的图片压缩方法

    Android应用开发中三种常见的图片压缩方法,分别是:质量压缩法.比例压缩法(根据路径获取图片并压缩)和比例压缩法(根据Bitmap图片压缩). 一.质量压缩法 private Bitmap com ...

  5. 三种常见的部署Kubernetes的方式

    三种常见的部署Kubernetes的方式 嘹亮的小号 Ghostcloud-001工号,资深Docker玩家,分布式系统研发11年. ​关注他   容器技术将应用程序及其依赖关系与操作系统进行分离,不 ...

  6. Spring源码分析之IOC的三种常见用法及源码实现(二)

    Spring源码分析之IOC的三种常见用法及源码实现(二) 回顾上文 我们研究的是 AnnotationConfigApplicationContext annotationConfigApplica ...

  7. iOS开发中深入理解CADisplayLink和NSTimer

    一.什么是CADisplayLink 简单地说,它就是一个定时器,每隔几毫秒刷新一次屏幕. CADisplayLink是一个能让我们以和屏幕刷新率相同的频率将内容画到屏幕上的定时器.我们在应用中创建一 ...

  8. ios 中定时器:NSTimer, CADisplayLink, GCD

    #import "ViewController.h" #import "RunloopViewController.h" @interface ViewCont ...

  9. 【转】IOS 计时器 NSTimer

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

随机推荐

  1. javascript模拟flash头像裁切上传

    是的,jq已经有类似的插件了,或者干脆用flash算了,为什么我还要自己写?因为造(wo)轮(bu)子(hui)也(flash)是一个学习的过程,轮子不会造,将来怎么造飞机?先来一张最终效果图: 一. ...

  2. win7 64位系统pdf预览

    装了Win7 64位以后,发现pdf文件不能正常预览,相信很多朋友也遇到了同样的问题,之前搜索的结果有个办法是安装Foxit的插件(相信有不少原来用Adobe Reader的用户从此改用Foxit了) ...

  3. div中嵌套img元素,4px空白

    写布局的过程中遇到一个问题,在div中嵌套了img元素,没有指定div的高度,嵌套之后div高度始终比img高4个像素,没有设置内外边距,找不到原因. 除非强制div的高度为img的高度,才能使div ...

  4. 点在多边形内算法,C#判断一个点是否在一个复杂多边形的内部

    判断一点是否在不规则图像的内部算法,如下图是由一个个点组成的不规则图像,判断某一点是否在不规则矩形内部,先上效果图 算法实现如下,算法简单,亲试有效 public class PositionAlgo ...

  5. Linux Shell脚本入门--wc命令

    wc 统计文件里面有多少单词,多少行,多少字符. wc语法 [root@www ~]# wc [-lwm] 选项与参数: -l :仅列出行: -w :仅列出多少字(英文单字): -m :多少字符: 默 ...

  6. [Office Web Apps]实现在线office文档预览

    摘要 在使用office web apps实现office文档在线预览的时候,需要注意的地方. web api web api作为owa在线预览服务回调的接口,这里面核心代码片段如下: using H ...

  7. 基于设备树的TQ2440 DMA学习(3)—— DMA控制器驱动

    作者 彭东林pengdonglin137@163.com 平台 TQ2440Linux-4.9 概述 上一篇直接操作DMA控制器实现了一个mem2mem的DMA传输,但是这样不符合linux driv ...

  8. ASP.NET Web API中实现版本的几种方式

    在ASP.NET Web API中,当我们的API发生改变,就涉及到版本问题了.如何实现API的版本呢? 1.通过路由设置版本 最简单的一种方式是通过路由设置,不同的路由,不同的版本,不同的contr ...

  9. SQLCE使用

    Windows Phone的本地数据库SQL Server CE是7.1版本即芒果更新的新特性,所以你要在应用程序中使用SQL Server CE数据库必须使用Windows Phone 7.1的AP ...

  10. 【工具类】怎么进入阿里云docker仓库

    进入阿里云docker仓库. 1.进入官网 2.选择 开发者  --->点击 阿里开源项目 3.选择  服务 点击代码托管.仓库 下的 容器镜像服务 4.点击进入 管理控制台 5.点击镜像搜索, ...