前言

相信一说到定时器, 我们使用最多的就是NSTimer 和 GCD 了, 还有另外一个高级的定时器 CADisplayLink;,下面将给大家详细介绍关于iOS定时器使用的相关内容,话不多说了,来一起看看详细的介绍吧。
一. NSTimer
NSTimer的初始化方法有以下几种:
会自动启动, 并加入 MainRunloop 的 NSDefaultRunLoopMode 中,
注意: 这里的自动启动, 并不是马上就会启动, 而是会延迟大概一个interval的时间:
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block
参数:
使用:
[NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
static NSInteger num = 0;
NSLog(@"%ld", (long)num);
num++;
if (num > 4) {
[timer invalidate];
NSLog(@"end");
}
}];
NSLog(@"start");
这时, 控制台的输出:
2016-12-29 16:29:53.901 定时器[11673:278678] start 2016-12-29 16:29:54.919 定时器[11673:278678] 0 2016-12-29 16:29:55.965 定时器[11673:278678] 1 2016-12-29 16:29:56.901 定时器[11673:278678] 2 2016-12-29 16:29:57.974 定时器[11673:278678] 3 2016-12-29 16:29:58.958 定时器[11673:278678] 4 2016-12-29 16:29:58.959 定时器[11673:278678] end
可以看出, 这里的internal设置为1s, 大概延迟了1s才开始执行block里的内容;
这里的停止定时器, 我直接在block里进行的, 如果使用一个全局变量来再其他地方手动停止定时器,需要这样进行:
[self.timer invalidate]; self.timer = nil;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo
参数:
示例:
// NSInvocation形式
- (void)timer2 {
NSMethodSignature *method = [ViewController instanceMethodSignatureForSelector:@selector(invocationTimeRun:)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:method];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 invocation:invocation repeats:YES];
// 设置方法调用者
invocation.target = self;
// 这里的SEL需要和NSMethodSignature中的一致
invocation.selector = @selector(invocationTimeRun:);
// 设置参数
// //这里的Index要从2开始,以为0跟1已经被占据了,分别是self(target),selector(_cmd)
// 如果有多个参数, 可依次设置3 4 5 ...
[invocation setArgument:&timer atIndex:2];
[invocation invoke];
NSLog(@"start");
}
- (void)invocationTimeRun:(NSTimer *)timer {
static NSInteger num = 0;
NSLog(@"%ld---%@", (long)num, timer);
num++;
if (num > 4) {
[timer invalidate];
}
}
输出:
2016-12-29 16:52:54.029 定时器[12089:289673] 0---<__NSCFTimer: 0x60000017d940> 2016-12-29 16:52:54.029 定时器[12089:289673] start 2016-12-29 16:52:55.104 定时器[12089:289673] 1---<__NSCFTimer: 0x60000017d940> 2016-12-29 16:52:56.095 定时器[12089:289673] 2---<__NSCFTimer: 0x60000017d940> 2016-12-29 16:52:57.098 定时器[12089:289673] 3---<__NSCFTimer: 0x60000017d940> 2016-12-29 16:52:58.094 定时器[12089:289673] 4---<__NSCFTimer: 0x60000017d940>
可以看出, 这里定时器是立马就执行了, 没有延迟;
此方法可以传递多个参数, 下面是传递两个参数的示例:
// NSInvocation形式
- (void)timer2 {
NSMethodSignature *method = [ViewController instanceMethodSignatureForSelector:@selector(invocationTimeRun:des:)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:method];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 invocation:invocation repeats:YES];
// 设置方法调用者
invocation.target = self;
// 这里的SEL需要和NSMethodSignature中的一致
invocation.selector = @selector(invocationTimeRun:des:);
// 设置参数
// //这里的Index要从2开始,以为0跟1已经被占据了,分别是self(target),selector(_cmd)
// 如果有多个参数, 可依次设置3 4 5 ...
[invocation setArgument:&timer atIndex:2];
// 设置第二个参数
NSString *dsc = @"第二个参数是字符串";
[invocation setArgument:&dsc atIndex:3];
[invocation invoke];
NSLog(@"start");
}
- (void)invocationTimeRun:(NSTimer *)timer des:(NSString *)dsc {
static NSInteger num = 0;
NSLog(@"%ld---%@--%@", (long)num, timer, dsc);
num++;
if (num > 4) {
[timer invalidate];
}
}
输出:
2016-12-29 16:57:45.087 定时器[12183:292324] 0---<__NSCFTimer: 0x60000016dbc0>--第二个参数是字符串 2016-12-29 16:57:45.088 定时器[12183:292324] start 2016-12-29 16:57:46.161 定时器[12183:292324] 1---<__NSCFTimer: 0x60000016dbc0>--第二个参数是字符串 2016-12-29 16:57:47.161 定时器[12183:292324] 2---<__NSCFTimer: 0x60000016dbc0>--第二个参数是字符串 2016-12-29 16:57:48.150 定时器[12183:292324] 3---<__NSCFTimer: 0x60000016dbc0>--第二个参数是字符串 2016-12-29 16:57:49.159 定时器[12183:292324] 4---<__NSCFTimer: 0x60000016dbc0>--第二个参数是字符串
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo
参数:
示例:
- (void)timer3 {
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(targetRun:) userInfo:@"这是携带的参数" repeats:YES];
NSLog(@"start");
}
- (void)targetRun:(NSTimer *)timer {
static NSInteger num = 0;
NSLog(@"%ld---%@--%@", (long)num, timer, timer.userInfo);
num++;
if (num > 4) {
[timer invalidate];
}
}
输出:
2016-12-29 17:05:11.590 定时器[12328:296879] start 2016-12-29 17:05:12.655 定时器[12328:296879] 0---<__NSCFTimer: 0x608000162700>--这是携带的参数 2016-12-29 17:05:13.661 定时器[12328:296879] 1---<__NSCFTimer: 0x608000162700>--这是携带的参数 2016-12-29 17:05:14.664 定时器[12328:296879] 2---<__NSCFTimer: 0x608000162700>--这是携带的参数 2016-12-29 17:05:15.651 定时器[12328:296879] 3---<__NSCFTimer: 0x608000162700>--这是携带的参数 2016-12-29 17:05:16.650 定时器[12328:296879] 4---<__NSCFTimer: 0x608000162700>--这是携带的参数
下面这三种方式创建定时器的用法, 和上面相应的方法类似, 需要注意的是, 这样创建的定时器, 并不会执行, 需要我们手动来开启定时器;
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo
开启的方式是, 将当前定时器添加到RunLoop中:
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
下面给出一个示例:
- (void)timer4 {
NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
static NSInteger num = 0;
NSLog(@"%ld", (long)num);
num++;
if (num > 4) {
[timer invalidate];
timer = nil;
NSLog(@"end");
}
}];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
NSLog(@"start");
}
输出:
2016-12-29 17:12:13.955 定时器[12498:301751] start 2016-12-29 17:12:15.013 定时器[12498:301751] 0 2016-12-29 17:12:16.018 定时器[12498:301751] 1 2016-12-29 17:12:17.011 定时器[12498:301751] 2 2016-12-29 17:12:18.024 定时器[12498:301751] 3 2016-12-29 17:12:19.023 定时器[12498:301751] 4 2016-12-29 17:12:19.023 定时器[12498:301751] end
定时器基本的创建方式就这些了, 还可以设置其他的属性, 例如开启时间, 这些直接参考其API 进行设置即可;
注意: 以上实例中, 我没有使用全局的NSTimer 对象, 如果设置全局变量, 或者设置为属性, 在停止定时器的时候要手动置为nil, 即:
[timer invalidate]; timer = nil;
二. GCD
dispatch_after : 延迟执行一次
dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block)
示例:
- (void)gcdTimer {
// 延迟2s
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC);
dispatch_after(delayTime, dispatch_get_main_queue(), ^(void){
NSLog(@"延迟2s后执行");
});
NSLog(@"start");
}
重复执行的定时器
void dispatch_source_set_timer(dispatch_source_t source, dispatch_time_t start, uint64_t interval, uint64_t leeway)
参数:
相关内容, 可参考文章: Dispatch Source Timer 的使用以及注意事项
// 重复执行的定时器
- (void)gcdTimer1 {
// 获取全局队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 创建定时器
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 开始时间
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
// dispatch_time_t start = dispatch_walltime(NULL, 0);
// 重复间隔
uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
// 设置定时器
dispatch_source_set_timer(_timer, start, interval, 0);
// 设置需要执行的事件
dispatch_source_set_event_handler(_timer, ^{
//在这里执行事件
static NSInteger num = 0;
NSLog(@"%ld", (long)num);
num++;
if (num > 4) {
NSLog(@"end");
// 关闭定时器
dispatch_source_cancel(_timer);
}
});
// 开启定时器
dispatch_resume(_timer);
NSLog(@"start");
}
输出:
2016-12-30 10:15:01.114 定时器[3393:99474] start 2016-12-30 10:15:02.187 定时器[3393:99796] 0 2016-12-30 10:15:03.114 定时器[3393:99796] 1 2016-12-30 10:15:04.186 定时器[3393:99796] 2 2016-12-30 10:15:05.188 定时器[3393:99796] 3 2016-12-30 10:15:06.188 定时器[3393:99796] 4 2016-12-30 10:15:06.188 定时器[3393:99796] end
这里的开始时间设置了1s的间隔, 所以1s之后才开始执行,可以设置使用DISPATCH_TIME_NOW来立马执行;
注意:
这里的开始时间(start)可以使用下面的方式的来设置:
dispatch_time_t start = dispatch_walltime(NULL, 0);
或者直接设置为: DISPATCH_TIME_NOW
关于 dispatch_walltime 和 dispatch_time 的区别, 上面也有提及,也可参考stackOverflow上的这个回答; 主要区别就是前者在系统休眠时还会继续计时, 而后者在系统休眠时就停止计时, 待系统重新激活时, 接着继续计时;
停止计时器:
停止GCD定时器的方式, Dispatch Source Timer 的使用以及注意事项中有提及, 主要有以下两种:
// 关闭定时器 // 完全销毁定时器, 重新开启的话需要重新创建 // 全局变量, 关闭后需要置为nil dispatch_source_cancel(_timer); // 暂停定时器 // 可使用dispatch_resume(_timer)再次开启 // 全局变量, 暂停后不能置为nil, 否则不能重新开启 dispatch_suspend(_timer);
三. CADisplayLink
CADisplayLink默认每秒运行60次,通过它的 frameInterval 属性改变每秒运行帧数,如设置为2,意味CADisplayLink每隔一帧运行一次,有效的逻辑每秒运行30次
屏幕刷新时调用:CADisplayLink是一个能让我们以和屏幕刷新率同步的频率将特定的内容画到屏幕上的定时器类。CADisplayLink以特定模式注册到runloop后,每当屏幕显示内容刷新结束的时候,runloop就会向CADisplayLink指定的target发送一次指定的selector消息, CADisplayLink类对应的selector就会被调用一次。所以通常情况下,按照iOS设备屏幕的刷新率60次/秒
延迟:iOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确度相当高。但如果调用的方法比较耗时,超过了屏幕刷新周期,就会导致跳过若干次回调调用机会。
如果CPU过于繁忙,无法保证屏幕60次/秒的刷新率,就会导致跳过若干次调用回调方法的机会,跳过次数取决CPU的忙碌程度。
使用场景:从原理上可以看出,CADisplayLink适合做界面的不停重绘,比如视频播放的时候需要不停地获取下一帧用于界面渲染。
+ (CADisplayLink *)displayLinkWithTarget:(id)target selector:(SEL)sel
参数:
示例:
- (void) displayLink {
CADisplayLink *display = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayRun:)];
// 大概1s执行一次
// 取值范围 1--100, 值越大, 频率越高
display.preferredFramesPerSecond = 2;
[display addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)displayRun:(CADisplayLink *)link {
static NSInteger num = 0;
NSLog(@"%ld", (long)num);
num++;
if (num > 4) {
[link invalidate];
NSLog(@"end");
}
}
这里的示例不太恰当, 不应该在这种场合使用,
另外, 我们可以使用他的 paused 属性, 来使其暂停, 或继续:
// 暂停 display.paused = YES; // 继续 display.paused = NO;
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
# ios
# 定时器的使用
# 定时器
# ios中定时器的使用
# iOS定时器的选择CADisplayLink NSTimer和GCD使用
# iOS DispatchSourceTimer 定时器的具体使用
# iOS中几种定时器的实现小结
# IOS 中NSTimer定时器的使用
# iOS仿小红书呼吸灯动画(核心动画和定时器)两种方式实现
# iOS开发定时器的三种方法分享
# iOS中的NSTimer定时器的初步使用解析
# iOS中GCD定时器详解
# iOS中的3种定时器汇总介绍
# 这是
# 第二个
# 就会
# 设置为
# 多个
# 计时器
# 可以看出
# 全局变量
# 跳过
# 相关内容
# 调用者
# 可以使用
# 百分百
# 回调
# 的是
# 自动启动
# 是一个
# 情况下
# 在这里
# 也有
相关文章:
建站主机系统SEO优化与智能配置核心关键词操作指南
深圳网站制作培训,深圳哪些招聘网站比较好?
全景视频制作网站有哪些,全景图怎么做成网页?
南阳网站制作公司推荐,小学电子版试卷去哪里找资源好?
制作充值网站的软件,做人力招聘为什么要自己交端口钱?
建站之星后台管理系统如何操作?
常州企业网站制作公司,全国继续教育网怎么登录?
已有域名和空间,如何快速搭建网站?
建站之星下载版如何获取与安装?
如何快速生成凡客建站的专业级图册?
已有域名能否直接搭建网站?
招贴海报怎么做,什么是海报招贴?
香港服务器部署网站为何提示未备案?
建站主机核心功能解析:服务器选择与网站搭建流程指南
长春网站建设制作公司,长春的网络公司怎么样主要是能做网站的?
高端智能建站公司优选:品牌定制与SEO优化一站式服务
如何快速完成中国万网建站详细流程?
香港服务器网站生成指南:免费资源整合与高速稳定配置方案
如何在景安服务器上快速搭建个人网站?
如何选择建站程序?包含哪些必备功能与类型?
制作网站的网址是什么,请问后缀为.com和.com.cn还有.cn的这三种网站是分别是什么类型的网站?
较简单的网站制作软件有哪些,手机版网页制作用什么软件?
建站之星价格显示格式升级,你的预算足够吗?
建站主机选哪家性价比最高?
宝塔面板创建网站无法访问?如何快速排查修复?
建站主机服务器选型指南与性能优化方案解析
宝塔新建站点报错如何解决?
头像制作网站在线制作软件,dw网页背景图像怎么设置?
Swift中循环语句中的转移语句 break 和 continue
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
阿里云网站搭建费用解析:服务器价格与建站成本优化指南
建站主机解析:虚拟主机配置与服务器选择指南
,有什么在线背英语单词效率比较高的网站?
html制作网站的步骤有哪些,iapp如何添加网页?
天河区网站制作公司,广州天河区如何办理身份证?需要什么资料有预约的网站吗?
北京营销型网站制作公司,可以用python做一个营销推广网站吗?
高防服务器租用指南:配置选择与快速部署攻略
沈阳制作网站公司排名,沈阳装饰协会官方网站?
如何快速查询网站的真实建站时间?
如何在新浪SAE免费搭建个人博客?
如何选择CMS系统实现快速建站与SEO优化?
如何在建站宝盒中设置产品搜索功能?
如何零成本快速生成个人自助网站?
如何快速选择适合个人网站的云服务器配置?
网站制作的软件有哪些,制作微信公众号除了秀米还有哪些比较好用的平台?
如何配置WinSCP新建站点的密钥验证步骤?
如何在VPS电脑上快速搭建网站?
如何通过商城免费建站系统源码自定义网站主题?
php json中文编码为null的解决办法
建站主机功能解析:服务器选择与快速搭建指南
*请认真填写需求信息,我们会在24小时内与您取得联系。