前言
NSTimer通常用来有一定时间跨度的周期性事件的处理
- 在指定的时间,执指定的任务(方法、动作)
- 每隔一段时间,执行制定任务(action)
I、定时器的基本用法
1.1 添加计时器
#pragma mark 添加计时器 - (void)addTimer{ [self processtime]; if (self.pics.count != 1) { // self.time = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(nextImage) userInfo:nil repeats:YES]; self.time = [NSTimer timerWithTimeInterval:5.0 target:self selector:@selector(nextImage) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:self.time forMode:NSRunLoopCommonModes]; [self.time setTolerance:1];//设置可以容忍的触发时间的延迟范围。 } }
每天创建NSTimer 都记得先判断当前的NSTimer属性是否移除运行循环
- (void)processtime{ if (_time) { if ([_time isValid]) { [_time invalidate]; _time = nil; } } }
1.2 往运行循环添加timer
iOS runloop 的基本使用
#pragma mark - 计时器的播放实现 - (IBAction)start{ NSLog(@"%s",__FUNCTION__); //间隔一秒更新counterLabel的显示 //计时器 //往运行循环添加timer的方式一:------------------------------------------- /** Creates and returns a new NSTimer object and schedules it on the current run loop in the default mode. 参数说明 1》seconds:double 时间间隔 2》target:The object to which to send the message specified by aSelector when the timer fires. 监听时钟触发的对象 3》Selector:The message to send to target when the timer fires.调用的方法 The selector should have the following signature: timerFireMethod: - (void)timerFireMethod:(NSTimer *)timer 4》userInfo: The user info for the timer.通常为nil,可用于区分计时器 repeats:if YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires.是否重复 */ // self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES]; //将timer添加到运行循环的方式二------------------------------------------- self.timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES]; //Registers a given timer with a given input mode.NSRunLoopCommonModes (监听滚动模式) [[NSRunLoop currentRunLoop] addTimer:self.timer forMode: NSRunLoopCommonModes]; }
1.3 UI 事件处理的NSRunLoopMode、和定时器的NSRunLoopMode 的关系是什么样的时候,可以保证它们能并发执行不影响个自的运行?
- 答:
定时器的model类型设置为NSRunLoopCommonModes
- 原因:
事件源,都是处于特定的模式下的,如果和当前runloop的模式不一致则不会得到响应;
创建一个 Timer 并加到 DefaultMode 时,Timer 会得到重复回调,但此时滑动一个TableView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,并且也不会影响到滑动操作。
因此想让Timer重复的得到回调,一种办法就是将这个 Timer 分别加入这两个 Mode。来保证主线程不管怎么切换model,timer都可以得到回调。
或者更简单的解决方式是加入NSRunLoopCommonModes
。
主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。这两个 Mode 都已经被标记为”Common”属性;这样timer会被 RunLoop 自动更新到所有具有”Common”属性的 Mode 里去`
- 注意:当 runloop 在使用任何 private mode (比如 _kCFStreamBlockingOpenMode、_kCFStreamSocketReadPrivateMode)时,你所设置的 NSTimer 任务还是会被冷落延后执行。
主线程 Runloop 大部分时候都是以 kCFRunLoopDefaultMode 和 UITrackingRunLoopMode 这两种 mode 运行
II 停止定时器的方案
2.1 invalidate的用法
- 开启一个定时任务,调用scheduleTimerWithTimeInterval:方法
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
每隔TimeInterval秒,调用一次target的selector方法,repeats决定了是否重复执行这个任务
- 调用
invalidate:
方法停止定时器工作
- (void)invalidate;//n一旦定时器被停止了,就不能再次执行任务。只能再创建一个新的定时器才能执行新的任务
2.2 FireDate的用法
先停止Timer,再某种情况下再次开启Timer
例子:在页面消失的时候关闭定时器,然后等页面再次打开的时候,又开启定时器。
主要是为了防止它在后台运行,暂用CPU
//页面将要进入前台,开启定时器 -(void)viewWillAppear:(BOOL)animated { //开启定时器 [scrollView.myTimer setFireDate:[NSDate distantPast]]; } //页面消失,进入后台不显示该页面,关闭定时器 -(void)viewDidDisappear:(BOOL)animated { //关闭定时器 [scrollView.myTimer setFireDate:[NSDate distantFuture]]; }
III CADisplayLink 与 NSTimer 有什么不同?
3.1 精确度
- IOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确度相当高。
CADisplayLink适用于“时间间隔比较短“的事件处理
- NSTimer的精确度就显得低了点,比如NSTimer的触发时间到的时候,runloop如果在阻塞状态,触发时间就会推迟到下一个runloop周期,导致任务的叠加。并且 NSTimer新增了tolerance属性,让用户可以设置可以容忍的触发的时间的延迟范围。
3.2 使用场合
CADisplayLink使用场合相对专一,适合做UI的不停重绘,比如自定义动画引擎或者视频播放的渲染。
NSTimer的使用范围要广泛的多,各种需要单次或者循环定时处理的任务都可以使用。
在UI相关的动画或者显示内容使用 CADisplayLink比起用NSTimer的好处就是我们不需要在格外关心屏幕的刷新频率了,因为它本身就是跟屏幕刷新同步的。
3.3 注意事项
- 通常来讲,iOS设备的刷新频率事60HZ也就是每秒60次。那么每一次刷新的时间就是1/60秒 大概16.7毫秒。当我们的frameInterval值为1的时候我们需要保证的是 CADisplayLink调用的`target`的函数计算时间不应该大于 16.7否则就会出现严重的丢帧现象。https://developer.apple.com/library/ios/documentation/QuartzCore/Reference/CADisplayLink_ClassRef/index.html
- 在mac应用中我们使用的不是CADisplayLink而是 CVDisplayLink它是基于C接口的用起来配置有些麻烦但是用起来还是很简单的。https://developer.apple.com/library/ios/samplecode/AVBasicVideoOutput/Introduction/Intro.html#//apple_ref/doc/uid/DTS40013109
- 一个类似Secret文字渐变效果的开源库 https://github.com/zipme/RQShineLabel/tree/master/Example/RQShineLabelDemo
IV、使用CALayer 实现时钟
https://blog.csdn.net/z929118967/article/details/74135552