iOS锦囊

iOS 三种常用定时器NSTimer、CADisplayLink

2018-01-24  本文已影响28人  雪碧童鞋

在iOS开发过程中,我们常常需要在某个时间后执行某个方法,或者是按照某个周期一直执行某个方法,这时我们就需要用到定时器,而在iOS中,常用的定时器有以下三种NSTimerCADisplayLinkGCD,下面对这几种方法的创建、执行、销毁及优缺点做个详解:

1. NSTimer

创建方式

//方式一
    self.timer = [NSTimer scheduledTimerWithTimeInterval:2
                                                  target:self
                                                selector:@selector(timerTest)
                                                userInfo:nil
                                                 repeats:YES];
//方式二
    self.timer = [NSTimer timerWithTimeInterval:2
                                         target:self
                                       selector:@selector(timerTest)
                                       userInfo:nil
                                        repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
定时执行(以下就是我们设置定时器需要做的事件)
- (void)timerTest {
    NSLog(@"==========NSTimer===============");
}

暂停、继续

暂停
self.timer.fireDate = [NSDate distantFuture];
继续
self.timer.fireDate = [NSDate distantPast];

销毁

  [self.timer invalidate];
  self.timer = nil;

RunLoop 有五种运行模式,其中第1、5种为苹果对外提供的mode

1. kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
2. UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
3. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
4. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
5. kCFRunLoopCommonModes: 这是一个占位用的Mode,作为标记kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一种真正的Mode
  1. 将NSTimer添加到两种模式下
  2. 使用占位的运行模式 NSRunLoopCommonModes标记,凡是被打上NSRunLoopCommonModes标记的都可以运行,而kCFRunLoopDefaultModeUITrackingRunLoopMode就被打上commonModel标记。

NSTimer 缺点

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

2.CADisplayLink

创建方式

 self.displayLink = [CADisplayLink displayLinkWithTarget:self
                                                   selector:@selector(timerTest)];
 [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

定时执行

- (void)timerTest {
    NSLog(@"==========CADisplayLink===============");
}

暂停、继续

添加一个按钮用于控制暂停继续(或其他点击事件)
pasued属性是控制计时器暂停与恢复,设置为YES的时候会暂停事件的触发。

- (void) displayLinkStart {
    self.displayLink.paused = !self.displayLink.paused;
}

销毁

- (void)stopDisplayLink {
    [self.displayLink invalidate];
    self.displayLink = nil;
}

优缺点

  1. 由于依托于屏幕刷新频率,若果CPU不堪重负而影响了屏幕刷新,那么我们的触发事件也会受到相应影响。
  2. selector触发的时间间隔只能是duration的整倍数
  3. selector事件如果大于其触发间隔就会造成掉帧现象。

相关属性

 @property(readonly, nonatomic) CFTimeInterval timestamp;    //获取上一次selector被执行的时间戳
 @property(readonly, nonatomic) CFTimeInterval duration; //获取当前设备的屏幕刷新时间间隔
 @property(getter=isPaused, nonatomic) BOOL paused;  //控制计时器暂停与恢复的属性
    
    //事件触发间隔。是指两次selector触发之间间隔几次屏幕刷新,默认值为1,也就是说屏幕每刷新一次,执行一次selector,这个也可以间接用来控制动画速度
 @property(nonatomic) NSInteger frameInterval
    CA_AVAILABLE_BUT_DEPRECATED_IOS (3.1, 10.0, 9.0, 10.0, 2.0, 3.0, "use preferredFramesPerSecond");
 @property(nonatomic) NSInteger preferredFramesPerSecond;

3. GCD-dispatch_source_t

创建 添加 执行方法

- (void)addDisPatch_source {
    //1.创建
    self.disTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    //2.设置时间
    dispatch_source_set_timer(self.disTimer, dispatch_walltime(NULL,0 * NSEC_PER_SEC), 1 * NSEC_PER_SEC, 0);
    //3.执行
    dispatch_source_set_event_handler(self.disTimer, ^{
        NSLog(@"=========dispatch_source_t=========");
    });
}

参数:

dispatch_source_create()相关参数

参数 意义
type dispatch源可处理的事件
handle 可以理解为句柄、索引或id,假如要监听进程,需要传入进程的ID
mask 可以理解为描述,提供更详细的描述,让它知道具体要监听什么
queue 自定义源需要的一个队列,用来处理所有的响应句柄(block)

dispatch_source_set_timer()相关参数

参数 意义
source dispatch_source_t
start 事件首次触发的延迟时间
interval 时间间隔
leeway 误差范围

开始 暂停

//开始
dispatch_resume(self.disTimer);
//暂停
dispatch_suspend(self.disTimer);

销毁

dispatch_source_cancel(self.disTimer);

注意:dispatch_source_t 一定要被设置为成员变量,否则将会立即被释放。

优缺点

上一篇下一篇

猜你喜欢

热点阅读