iOS定时器的应用

1,196 阅读5分钟

这是我参与8月更文挑战的第26天,活动详情查看: 8月更文挑战” juejin.cn/post/698796… ”

前言

NSTimer通常用来有一定时间跨度的周期性事件的处理

  1. 在指定的时间,执指定的任务(方法、动作)
  2. 每隔一段时间,执行制定任务(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 的基本使用

blog.csdn.net/z929118967/…

#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的用法

  1. 开启一个定时任务,调用scheduleTimerWithTimeInterval:方法
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;

每隔TimeInterval秒,调用一次target的selector方法,repeats决定了是否重复执行这个任务

  1. 调用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 精确度

  1. IOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确度相当高。

CADisplayLink适用于“时间间隔比较短“的事件处理

  1. NSTimer的精确度就显得低了点,比如NSTimer的触发时间到的时候,runloop如果在阻塞状态,触发时间就会推迟到下一个runloop周期,导致任务的叠加。并且 NSTimer新增了tolerance属性,让用户可以设置可以容忍的触发的时间的延迟范围。

3.2 使用场合

CADisplayLink使用场合相对专一,适合做UI的不停重绘,比如自定义动画引擎或者视频播放的渲染。

NSTimer的使用范围要广泛的多,各种需要单次或者循环定时处理的任务都可以使用。

在UI相关的动画或者显示内容使用 CADisplayLink比起用NSTimer的好处就是我们不需要在格外关心屏幕的刷新频率了,因为它本身就是跟屏幕刷新同步的。

3.3 注意事项

  1. 通常来讲,iOS设备的刷新频率事60HZ也就是每秒60次。那么每一次刷新的时间就是1/60秒 大概16.7毫秒。当我们的frameInterval值为1的时候我们需要保证的是 CADisplayLink调用的`target`的函数计算时间不应该大于 16.7否则就会出现严重的丢帧现象。developer.apple.com/library/ios…
  2. 在mac应用中我们使用的不是CADisplayLink而是 CVDisplayLink它是基于C接口的用起来配置有些麻烦但是用起来还是很简单的。 developer.apple.com/library/ios…
  3. 一个类似Secret文字渐变效果的开源库 github.com/zipme/RQShi…

IV、使用CALayer 实现时钟

blog.csdn.net/z929118967/…

see also

iOS 利用UIScrollView实现图片放大预览,并支持缩小

blog.csdn.net/z929118967/…

更多内容请查看原文或者关注公众号:iOS逆向