iOS - OC NSTimer 定时器
前言
@interface NSTimer : NSObject
@interface CADisplayLink : NSObject
- 作用
- 在指定的时间执行指定的任务。
- 每隔一段时间执行指定的任务。
1、定时器的创建
1.1 NSTimer 定时器
当定时器创建完(不用 scheduled 的,添加到 runloop 中)后,该定时器将在初始化时指定的 ti 秒后自动触发。如果 NSTimer 的触发时间到的时候,runloop 在阻塞状态,触发时间就会推迟到下一个 runloop 周期。
1、scheduled 方式
创建并启动定时器。
默认将时钟以 NSDefaultRunLoopMode 模式添加到运行循环。
发生用户交互的时候,时钟会被暂停。
/*
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)yesOrNo; 参数:
TimeInterval:触发时间,单位秒
target:定时起触发对象
selector:定时器响应方法
userInfo:用户信息
repeats:是否重复执行,YES 每个指定的时间重复执行,NO 只执行一次
*/ // 创建并启动定时器
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(updateTimer:)
userInfo:nil
repeats:YES];
2、timer 方式
创建定时器,添加到运行循环后启动定时器。
将时钟以指定的模式添加到运行循环。
/*
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(nullable id)userInfo
repeats:(BOOL)yesOrNo; - (void)addTimer:(NSTimer *)timer forMode:(NSString *)mode; NSDefaultRunLoopMode:发生用户交互的时候,时钟会被暂停。时钟,网络。
NSRunLoopCommonModes:发生用户交互的时候,时钟仍然会触发,如果时钟触发方法非常耗时,
使用此方式时用户操作会造成非常严重的卡顿。用户交互,响应级别高。
*/ // 创建定时器
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0
target:self
selector:@selector(updateTimer:)
userInfo:nil
repeats:YES]; // 将定时器添加到运行循环
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
1.2 CADisplayLink 定时器
1、CADisplayLink
CADisplayLink 是一个能让我们以和屏幕刷新率相同的频率将内容画到屏幕上的定时器。我们在应用中创建一个新的 CADisplayLink 对象,把它添加到一个 runloop 中,并给它提供一个 target 和 selector 在屏幕刷新的时候调用。
一但 CADisplayLink 以特定的模式注册到 runloop 之后,每当屏幕需要刷新的时候,runloop 就会调用 CADisplayLink 绑定的 target 上的 selector,这时 target 可以读到 CADisplayLink 的每次调用的时间戳,用来准备下一帧显示需要的数据。例如一个视频应用使用时间戳来计算下一帧要显示的视频数据。在 UI 做动画的过程中,需要通过时间戳来计算 UI 对象在动画的下一帧要更新的大小等等。
在添加进 runloop 的时候我们应该选用高一些的优先级,来保证动画的平滑。可以设想一下,我们在动画的过程中,runloop 被添加进来了一个高优先级的任务,那么,下一次的调用就会被暂停转而先去执行高优先级的任务,然后在接着执行 CADisplayLink 的调用,从而造成动画过程的卡顿,使动画不流畅。
另外 CADisplayLink 不能被继承。
属性:
duration :提供了每帧之间的时间,也就是屏幕每次刷新之间的的时间。我们可以使用这个时间来计算出下一帧要显示
的 UI的数值。但是 duration 只是个大概的时间,如果 CPU 忙于其它计算,就没法保证以相同的频率
执行屏幕的绘制操作,这样会跳过几次调用回调方法的机会。 frameInterval :可读可写的 NSInteger 型值,标识间隔多少帧调用一次 selector 方法,默认值是 1,即每帧都调
用一次。如果每帧都调用一次的话,对于 iOS 设备来说那刷新频率就是 60HZ 也就是每秒 60 次,如果
将 frameInterval 设为 2 那么就会两帧调用一次,也就是变成了每秒刷新 30 次。 pause :控制 CADisplayLink 的运行。当我们想结束一个 CADisplayLink 的时候,应该调用
`- (void)invalidate`从 runloop 中删除并删除之前绑定的 target 跟 selector。
2、CADisplayLink 与 NSTimer 有什么不同
- iOS 设备的屏幕刷新频率是固定的,CADisplayLink 在正常情况下会在每次刷新结束都被调用,精确度相当高。
- NSTimer 的精确度就显得低了点,比如 NSTimer 的触发时间到的时候,runloop 如果在阻塞状态,触发时间就会推迟到下一个 runloop 周期。并且 NSTimer 新增了 tolerance 属性,让用户可以设置可以容忍的触发的时间的延迟范围。
- CADisplayLink 使用场合相对专一,适合做 UI 的不停重绘,比如自定义动画引擎或者视频播放的渲染。NSTimer 的使用范围要广泛的多,各种需要单次或者循环定时处理的任务都可以使用。在 UI 相关的动画或者显示内容使用 CADisplayLink 比起用 NSTimer 的好处就是我们不需要再格外关心屏幕的刷新频率了,因为它本身就是跟屏幕刷新同步的。
3、CADisplayLink 使用示例
@property (nonatomic, strong) CADisplayLink *link; // 创建定时器
self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(angleChange)];
[self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; // 开启定时器,默认
self.link.paused = NO; // 暂停定时器
self.link.paused = YES; // 定时器触发事件处理
- (void)angleChange { }
@property (nonatomic, strong) CADisplayLink *displayLink; self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateTextColor)];
self.displayLink.paused = YES;
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; - (void)updateTextColor { } - (void)startAnimation {
self.beginTime = CACurrentMediaTime();
self.displayLink.paused = NO;
} - (void)stopAnimation {
self.displayLink.paused = YES;
[self.displayLink invalidate];
self.displayLink = nil;
}
4、给非 UI 对象添加动画效果
- 我们知道动画效果就是一个属性的线性变化,比如 UIView 动画的 EasyIn EasyOut 。通过数值按照不同速率的变化我们能生成更接近真实世界的动画效果。我们也可以利用这个特性来使一些其他属性按照我们期望的曲线变化。比如当播放视频时关掉视频的声音我可以通过 CADisplayLink 来实现一个 EasyOut 的渐出效果:先快速的降低音量,在慢慢的渐变到静音。
5、注意
通常来讲:iOS 设备的刷新频率事 60HZ 也就是每秒 60 次。那么每一次刷新的时间就是 1/60 秒 大概 16.7 毫秒。当我们的 frameInterval 值为 1 的时候我们需要保证的是 CADisplayLink 调用的 target 的函数计算时间不应该大于 16.7 否则就会出现严重的丢帧现象。
在 Mac 应用中我们使用的不是 CADisplayLink 而是 CVDisplayLink 它是基于 C 接口的用起来配置有些麻烦但是用起来还是很简单的。
2、定时器的启动与关闭
// 启动定时器
[timer setFireDate:[NSDate distantPast]];
// 暂停定时器
[timer setFireDate:[NSDate distantFuture]];
// 关闭定时器,永久关闭定时器
[timer invalidate];
3、子线程定时器的创建
在子线程创建定时器时,需要手动开启子线程的运行循环。
dispatch_async(dispatch_get_global_queue(0, 0), ^{ // 在子线程创建定时器
/*
scheduled 或 timer 方式创建
*/
self.timer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:@selector(updateTimer:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode]; // 启动子线程的运行循环
/*
这句代码就是一个死循环!如果不停止运行循环,不会执行添加到此句之后的任何代码
*/
CFRunLoopRun(); // 停止子线程运行循环之前,不会执行添加到此处的任何代码
});
// 定时器执行操作方法 - (void)updateTimer { static int num = 0; num++; // 满足条件后,停止当前的运行循环
if (num == 8) { // 停止当前的运行循环
/*
一旦停止了运行循环,后续代码能够执行,执行完毕后,线程被自动销毁
*/
CFRunLoopStop(CFRunLoopGetCurrent());
}
}
4、定时任务
1)performSelector
// 延时调用
/*
1.5 秒后自动调用 self 的 hideHUD 方法
*/
[self performSelector:@selector(hideHUD) withObject:nil afterDelay:1.5]; // 取消延时调用
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideHUD) object:nil];
2)GCD
// 多线程
/*
1.5 秒后自动执行 block 里面的代码
*/
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.hud.alpha = 0.0;
});
3)NSTimer
// 定时器
/*
1.5 秒后自动调用 self 的 hideHUD 方法
*/
[NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(hideHUD) userInfo:nil repeats:NO];
iOS - OC NSTimer 定时器的更多相关文章
- iOS - Swift NSTimer 定时器
前言 public class NSTimer : NSObject 作用 在指定的时间执行指定的任务. 每隔一段时间执行指定的任务. 1.定时器的创建 当定时器创建完(不用 scheduled 的, ...
- IOS OC 多任务定时器 NSRunLoop 管理 NSTimer
下面有两种做法 1.使用日期组件 NSDateComponents 2.使用NSString 生成一个日期 // 创建一个日历对象 NSCalendar *calendar = [NSCalenda ...
- IOS中的NSTimer定时器详解
/* 在IOS中有多种定时器,这里我对NSTimer定时器做了一个简单的介绍.如果你是小白,你可能会从这篇文章中学习到一些知识,如果你是大牛,请别吝啬你的评论,指出我的不足,你的质疑是对我最大的帮助. ...
- iOS中的定时器
据我所知,iOS中的定时器有两种.一个叫NSTimer,一个叫CADisplayLink.还有一种是使用GCD,不常用,这里就不介绍了. 下边说下两个定时器分别得用法: =============== ...
- iOS - OC 面向对象语法
1.类 1)根类:因为类 NSObject 是层次结构的最顶层,因此称为根类. 可以将类称为子类(subclass)和父类(superclass),也可以将类称为子类和超类. 2)分类/类别(cate ...
- ios+oc面试题
ios+oc面试题 浅复制和深复制的区别?//浅拷贝和深拷贝答案:浅层复制(copy):只复制指向对象的指针,而不复制引用对象本身.//通过对象的指针来访问这个对象深层复制(mutableCo ...
- iOS OC语言原生开发的IM模块--RChat
iOS OC语言原生开发的IM模块,用于项目中需要原生开发IM的情况,具备发送文字.表情.语音.图片.视频等完整功能,包含图片预览视频播放等功能,此项目将会长期更新如有问题可以提出,我的邮箱:fshm ...
- 【转】IOS NSTimer 定时器用法总结
原文网址:http://my.oschina.net/u/2340880/blog/398598 NSTimer在IOS开发中会经常用到,尤其是小型游戏,然而对于初学者时常会注意不到其中的内存释放问题 ...
- iOS三种定时器的用法NSTimer、CADisplayLink、GCD
一,NSTimer //创建方式1 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector: ...
随机推荐
- Array JSON
Tool: Online jsonviewer JSON: JavaScript Object Notation. JSON is a syntax for storing and exchangin ...
- PHP弱类型安全问题的写法和步骤
鉴于目前PHP是世界上最好的语言,PHP本身的问题也可以算作是web安全的一个方面.在PHP中的特性就是弱类型,以及内置函数对于传入参数的松散处理.本篇文章主要就是记录我在做攻防平台上面遇到的PHP的 ...
- ThinkPHP跳转与重定向的区别在哪里
跳转: 浏览器认为 : 当前 URL 请求成功 , 重新请求新的 URL . 浏览器会记录当前的 URL 和新的 URL 在请求历史记录中. 回退, 是可以回退到 , 当前的 URL 上的 . ( 无 ...
- ORACLE--分区表数据清理
由于分区表数据增加:没做清除操作:导致表空间告急.需要清理很久之前的数据:释放空间.步骤如下 一,查看哪个表占的空间 SELECT t.segment_name, SUM(t.bytes / 1024 ...
- Effective C++第三遍
试图调用private的copy或赋值函数是编译期错误,而调用没有具体定义的函数则是连接期错误. 以对象管理资源:智能指针RAII(资源获取立即初始化)后都是对象,但有时候,比如(API的)函数参数要 ...
- YTU 2989: 顺序表基本运算(线性表)
2989: 顺序表基本运算(线性表) 时间限制: 1 Sec 内存限制: 128 MB 提交: 1 解决: 1 题目描述 编写一个程序,实现顺序表的各种基本运算(假设顺序表的元素类型为char), ...
- js中的各种获取日期
JS中获取当前时间点前一天时间 var date=new Date(); var dat_year=date.getYear(); var dat_month=date.getMonth(); var ...
- Unity脚本在层级面板中的执行顺序测试2
上一篇测试了生成顺序对执行顺序的影响,链接:LINK 执行顺序测试3: LINK 这篇主要测试一下Awake,OnEnable,Start三个常用消息的循环顺序 1.测试消息循环顺序 先上一个最简单的 ...
- c++中函数empty()怎么使用
string s = "";if (s.empty()){ cout << "字符串为空..";}else{ cout << " ...
- ecshop商品分类页获取相册列表方法
第1步:找到根目录的category.php文件,查找约:486行左右(注意这不是准确位置,看实际的哦),找到这个函数: /** * 获得分类下的商品 * * @access public * @pa ...