iOS之三大定时器


iOS开发中定时器经常会用到,iOS中常用的定时器有三种,分别是NSTime,CADisplayLink和GCD。

一, NSTimer

方式1

    // 创建定时器
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(test) userInfo:nil repeats:YES];
    // 停止定时器
    [timer invalidate];

方式2

    // 创建定时器
    NSTimer *timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(test) userInfo:nil repeats:YES];
    // 将定时器添加到runloop中,否则定时器不会启动
    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    // 停止定时器
    [timer invalidate];

方式1:会自动将创建的定时器以默认方式添加到当前线程runloop中,而无需手动添加。但是在此种模式下,当滚动屏幕时runloop会进入另外一种模式,定时器会暂停,为了解决这种问题,可以

方式2:那样把定时器添加到NSRunLoopCommonModes模式下。

方式1和方式2在设置后都会在间隔设定的时间(本例中设置为2s)后执行test方法,如果需要立即执行可以使用下面的代码。

[time fire];

关于NSTimer的开始,暂停,继续,销毁

-(IBAction)btnClick{
    [self starTimer];//开始计时
    //[self stopTimer];
}
 
-(NSTimer*)timer{
    if (!_timer) {
        _timer =[NSTimer scheduledTimerWithTimeInterval:5  target:self  selector:@selector(beginChange) userInfo:nil  repeats:YES];
    }
    return _timer;
}
 
//暂停定时器(只是暂停,并没有销毁timer)
-(void)pauseTimer{
    [self.timer setFireDate:[NSDate distantFuture]];
}
//继续计时 -(void)continueTimer{ [self.timer setFireDate:[NSDate distantPast]]; } //开始计时 -(void)startimer{ [self.timer fire]; } //暂停并销毁 -(void)stopTimer{ [self.timer invalidate]; self.timer = nil; } //开启定时器 -(void)starTimer{ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(timerStar) object:nil]; [self performSelector:@selector(timerStar) withObject:nil afterDelay:1]; }

二, CADisplayLink

// 创建displayLink
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(test:)];
// 将创建的displaylink添加到runloop中,否则定时器不会执行
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

// 停止定时器
[displayLink invalidate];
 displayLink = nil;

当把CADisplayLink对象add到runloop中后,selector就能被周期性调用,类似于重复的NSTimer被启动了;执行invalidate操作时,CADisplayLink对象就会从runloop中移除,selector调用也随即停止,类似于NSTimer的invalidate方法

调用时机

CADisplayLink是一个和屏幕刷新率同步的定时器类。CADisplayLink以特定模式注册到runloop后,每当屏幕显示内容刷新结束的时候,runloop就会向CADisplayLink指定的target发送一次指定的selector消息,CADisplayLink类对应的selector就会被调用一次,所以可以使用CADisplayLink做一些和屏幕操作相关的操作。

重要属性
  • frameInterval (时间戳)

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

  • duration (时间间隔)

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

  • isPaused (暂停/开启) 

    isPaused设置为true时可以用于暂停通知
  • 修改帧率

    修改帧率: 如果在特定帧率内无法提供对象的操作,可以通过降低帧率解决.一个拥有持续稳定但是较慢帧率的应用要比跳帧的应用顺滑的多.
    可以通过preferredFramesPerSecond来设置每秒刷新次数.preferredFramesPerSecond默认值为屏幕最大帧率(maximumFramesPerSecond),目前是60.
    实际的屏幕帧率会和preferredFramesPerSecond有一定的出入,结果是由设置的值和屏幕最大帧率(maximumFramesPerSecond)相互影响产生的.规则大概如下:

    如果屏幕最大帧率(preferredFramesPerSecond)是60,实际帧率只能是15, 20, 30, 60中的一种.如果设置大于60的值,屏幕实际帧率为60.如果设置的是26~35之间的值,实际帧率是

 注意:

        注意CADisplayLink是不能被继承的.

三, GCD定时器

一次性定时
 dispatch_time_t timer = dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC);
 dispatch_after(timer, dispatch_get_main_queue(), ^(void){
        NSLog(@"GCD-----%@",[NSThread currentThread]);
 });

 

重复执行的定时器
@property (nonatomic ,strong)dispatch_source_t timer;//  注意:此处应该使用强引用 strong
{
    //0.创建队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    //1.创建GCD中的定时器
    /*
     第一个参数:创建source的类型 DISPATCH_SOURCE_TYPE_TIMER:定时器
     第二个参数:0
     第三个参数:0
     第四个参数:队列
     */
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

    //2.设置时间等
    /*
     第一个参数:定时器对象
     第二个参数:DISPATCH_TIME_NOW 表示从现在开始计时
     第三个参数:间隔时间 GCD里面的时间最小单位为 纳秒
     第四个参数:精准度(表示允许的误差,0表示绝对精准)
     */
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);

    //3.要调用的任务
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"GCD-----%@",[NSThread currentThread]);
    });

    //4.开始执行
    dispatch_resume(timer);

    //
    self.timer = timer;
}
注意:
  • dispatch_source_t 在本质上是一个对象,所以我们使用强引用。我们可以点击dispatch_source_t跳转到source.h文件看到,改对象使用宏定义,进行了一系列操作定义对象。
    dispatch_source_t展开后的定义是:

@protocol OS_dispatch_source <OS_dispatch_object>
@end
typedef NSObject<OS_dispatch_source>* dispatch_source_t

   也就是dispatch_source_t 就是一个NSObjective对象。对于想深入了解的同学自行百度(主要是本人实在没有那么多精力看源码)

  • 定时器的暂停使用的是:dispatch_cancel(self.timer) 很明显这个我们可以清楚得看到也是一个宏定义,至于他的内部操作,请参考上一句话
  • 相对于NSTimer来说GCD定时器更加精确,并且不用考虑运行模式,因为NSTimer其实是延迟把事件放到RunLoop中执行,如果遇到其他的事件导致NSTimer的事件执行错过了运行周期,就会导致NSTimer的事件要到下一个周期才能运行。
  • 此处注意一定要强引用定时器 ,否则定时器执行到 } 后将会被释放,无定时效果。
  • GCD定时器时间非常精准,最小的定时时间可以达到1纳秒,所以用在非常精确的定时场合。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM