这是我参与8月更文挑战的第26天,活动详情查看: 8月更文挑战” juejin.cn/post/698796… ”
前言
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
#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事件的影响
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否则就会出现严重的丢帧现象。developer.apple.com/library/ios…
- 在mac应用中我们使用的不是CADisplayLink而是 CVDisplayLink它是基于C接口的用起来配置有些麻烦但是用起来还是很简单的。 developer.apple.com/library/ios…
- 一个类似Secret文字渐变效果的开源库 github.com/zipme/RQShi…
IV、使用CALayer 实现时钟
see also
iOS 利用UIScrollView实现图片放大预览,并支持缩小
更多内容请查看原文或者关注公众号:iOS逆向