iOS 定时器

一,NSTimer

1.调用计时器方法:

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(action:) userInfo:nil repeats:NO];
TimerInterval : 执行之前等待的时间。比如设置成1.0,就代表1秒后执行方法
target : 需要执行方法的对象。
selector  : 需要执行的方法

repeats : 是否需要循环

2.释放计时器的方法:(是永久释放)

[timer invalidate];
timer = nil;

要想实现:先停止,然后再某种情况下再次开启运行timer,可以使用下面的方法:

首先关闭定时器不能使用上面的方法,应该使用下面的方法:

//关闭定时器  
[myTimer setFireDate:[NSDate distantFuture]]; 
然后就可以使用下面的方法再此开启这个timer了:
//开启定时器  
[myTimer setFireDate:[NSDate distantPast]]; 
注意 :
调用创建方法后, target 对象的计数器会加1,直到执行完毕,自动减1。

如果是循环执行的话,就必须手动关闭,否则可以不执行释放方法。

将计数器的repeats设置为YES的时候,self的引用计数会加1。因此可能会导致self(即viewController)不能release,所以,必须在viewWillAppear的时候,将计数器timer停止,否则可能会导致内存泄露。

3.特性

  • 存在延迟
    不管是一次性的还是周期性的timer的实际触发事件的时间,都会与所加入的RunLoopRunLoop Mode有关,如果此RunLoop正在执行一个连续性的运算,timer就会被延时出发。重复性的timer遇到这种情况,如果延迟超过了一个周期,则会在延时结束后立刻执行,并按照之前指定的周期继续执行。

  • 必须加入Runloop
    使用上面的创建方式,会自动把timer加入MainRunloopNSDefaultRunLoopMode中。如果使用以下方式创建定时器,就必须手动加入Runloop:

    NSTimer *timer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];


    二、CADisplayLink

    1.创建方法
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];    
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    2.停止
    [self.displayLink invalidate];  
    self.displayLink = nil;
    当把 CADisplayLink 对象 add runloop 中后, selector 就能被周期性调用,类似于重复的 NSTimer 被启动了;执行 invalidate 操作时, CADisplayLink 对象就会从 runloop 中移除, selector 调用也随即停止,类似于 NSTimer invalidate 方法。

    3.注意:

    1. 特性

      • 屏幕刷新时调用
        CADisplayLink是一个能让我们以和屏幕刷新率同步的频率将特定的内容画到屏幕上的定时器类。CADisplayLink以特定模式注册到runloop后,每当屏幕显示内容刷新结束的时候,runloop就会向CADisplayLink指定的target发送一次指定的selector消息, CADisplayLink类对应的selector就会被调用一次。所以通常情况下,按照iOS设备屏幕的刷新率60次/秒

      • 延迟
        iOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确度相当高。但如果调用的方法比较耗时,超过了屏幕刷新周期,就会导致跳过若干次回调调用机会。
        如果CPU过于繁忙,无法保证屏幕60次/秒的刷新率,就会导致跳过若干次调用回调方法的机会,跳过次数取决CPU的忙碌程度。

    2. 使用场景
      从原理上可以看出,CADisplayLink适合做界面的不停重绘,比如视频播放的时候需要不停地获取下一帧用于界面渲染。

    3. 重要属性

      • frameInterval
        NSInteger类型的值,用来设置间隔多少帧调用一次selector方法,默认值是1,即每帧都调用一次。

      • duration
        readOnlyCFTimeInterval值,表示两次屏幕刷新之间的时间间隔。需要注意的是,该属性在targetselector被首次调用以后才会被赋值。selector的调用间隔时间计算方式是:调用间隔时间 = duration × frameInterval

    三、dispatch_source

    1. 创建方法

    //第一种 每一秒执行一次(重复性)  
    double delayInSeconds = 1.0;  
    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));  
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC, 0.0);  
    dispatch_source_set_event_handler(timer, ^{  
        NSLog(@"timer date 1== %@",[NSDate date]);  
    });  
    dispatch_resume(timer);  
      
    //第二种 二秒后执行 (一次性)  
    double delayInSeconds = 2.0;  
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));  
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){  
        NSLog(@"timer date 2== %@",[NSDate date]);  
    });  
    <span style="font-family: 'Helvetica Neue', Helvetica, STheiti, 微软雅黑, 黑体, Arial, Tahoma, sans-serif, serif; font-size: 14px; background-color: rgb(255, 255, 255);">2.停止方法</span>
    <span style="font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace; font-size: 14px; background-color: rgb(255, 255, 255);">dispatch_source_cancel(_timer);</span>

3.特性.默认是重复执行的,可以在事件响应回调中通过dispatch_source_cancel方法来设置为只执行一次,如下代码:

dispatch_source_set_event_handler(_timer, ^{
    //执行事件
    dispatch_source_cancel(_timer);});
4.属性

dispatch_source_set_timer(dispatch_source_t source, 
                          dispatch_time_t start,
                          uint64_t interval, 
                          uint64_t leeway);

  • start
    计时器起始时间,可以通过dispatch_time创建,如果使用DISPATCH_TIME_NOW,则创建后立即执行

  • interval
    计时器间隔时间,可以通过timeInterval * NSEC_PER_SEC来设置,其中,
    timeInterval为对应的秒数

  • leeway
    这个参数的理解,我觉得http://www.dreamingwish.com上Seven's
    同学的解释很直观也很易懂:“这个参数告诉系统我们需要计时器触发的精准程度。所有的计时器都不会保证100%精准,这个参数用来告诉系统你希望系统保证精准的努力程度。如果你希望一个计时器没五秒触发一次,并且越准越好,那么你传递0为参数。另外,如果是一个周期性任务,比如检查email,那么你会希望每十分钟检查一次,但是不用那么精准。所以你可以传入60,告诉系统60秒的误差是可接受的。这样有什么意义呢?简单来说,就是降低资源消耗。如果系统可以让cpu休息足够长的时间,并在每次醒来的时候执行一个任务集合,而不是不断的醒来睡去以执行任务,那么系统会更高效。如果传入一个比较大的leeway给你的计时器,意味着你允许系统拖延你的计时器来将计时器任务与其他任务联合起来一起执行。

  1. 优点:

    • 时间准确

    • 可以使用子线程,解决定时间跑在主线程上卡UI问题

  2. 注意事项:
    需要将dispatch_source_t timer设置为成员变量,不然会立即释放





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值