iOS-定时器功能的实现
方式一:NSTimer
1.创建方法:
1.1 //需手动加入RunLoop
/*
TimeInterval:执行之前等待的时间。比如设置成1.0,就代表1秒后执行方法
target:需要执行方法的对象
selector:需要执行的方法
repeats:是否需要循环
*/
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
1.2 //自动将 timer加入到当前线程的RunLoop中
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
1.3 //Block方法,iOS 10新出的API,使用这个两个方法,要考虑到兼容性问题
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
1.4 暂停、开始定时器
/** < 开始定时器 > */if(self.timer.isValid) { self.timer.fireDate = [NSDate date]; } /** < 暂停定时器 > */if(self.timer.isValid) { self.timer.fireDate = [NSDate distantFuture]; }
1.5 销毁定时器
[self.timer invalidate];
self.timer = nil;
1.6 解决循环引用
(稍后记录下来)
1.7 缺点
--- 易造成循环引用
---NSTimer 的定时器是在 RunLoop 中实现的,由于RunLoop在处理各种任务,所以会造成计时器不够准确,有时候会相对慢一些
方式二:CGD
1.简单实现-dispatch_after -- 延时执行,只执行一次,执行完后,就不再执行,如果重复某个操作,需要加逻辑实现不断调用
//延时执行dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2*NSEC_PER_SEC)),dispatch_get_main_queue(),^{NSLog(@"-------延时执行--------");});
缺点:
无法取消
2.复杂方法
2.1 创建
@property (noatomic, strong) dispatch_source_t timer;
//获取队列,这里获取全局队列(tips:可以单独创建一个队列跑定时器)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//创建定时器(dispatch_source_t本质还是个OC对象)
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//start参数控制计时器第一次触发的时刻,延迟0s
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, 0 * NSEC_PER_SEC);
// dispatch_time_t start = dispatch_walltime(NULL, 0);
//每隔1s执行一次
uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
dispatch_source_set_timer(self.timer, start, interval, 0);
dispatch_source_set_event_handler(self.timer, ^{
//要执行的任务
});
//开始执行定时器
dispatch_resume(self.timer);
2.2 开始定时器
dispatch_resume(self.timer);
2.3 暂停定时器
dispatch_suspend(self.timer);
2.4 取消定时器
dispatch_cancel(self.timer);
self.timer = nil;
2.5 优点
精准
方案三:performSelector
- (void)performSelector:(SEL)aSelector withObject:(nullableid)anArgument afterDelay:(NSTimeInterval)delay;
也是延时一次,跟 dispatch_after 类似,但是可以随时取消,内部实现其实也是开启了一个定时器
优点:
可取消
方案四:CADisplayLink
创建
/** < 创建CADisplayLink > */
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(printSeconds)];
/** < 设置每秒刷新一次 The default value is 60 > */
self.displayLink.preferredFramesPerSecond = 1;
/** < 注册到RunLoop中 NSDefaultRunLoopMode > */
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop]forMode:NSDefaultRunLoopMode];
/** < 暂停定时器 Initial state isfalse> */
self.displayLink.paused = YES;
暂停self.displayLink.paused = YES;
开始self.displayLink.paused = NO;
销毁
/** < 销毁定时器 > */ [self.displayLink invalidate]; self.displayLink = nil;复制代码
最后CADisplayLink相比NSTimer来说,精度要高的多,如果有想更深入的了解可以查看官方文档或相关博客(CADisplayLink)介绍的很详细。
参考链接:
https://juejin.im/post/5a371c995188256970781316