iOS中的各种Timer(含实例代码)

编写App工程中,会遇到各种定时器的问题:比如某个页面上的数据定时刷新,需要在定时器中反复向服务器发送请求;首页广告位(Banner)的图片不断滚动,需要在定时器中设定变换的间隔时间;收到用户手势交互时,出现响应动画,可以通过定时器设置不同动画连续执行等等。iOS中的Timer可以通过三种方式来实现:NSTimer,dispatch,CADisplayLink,其执行的精确度依次提高。下面介绍一下各自的使用方式。

NSTimer

NSTimer是OC以面向对象方式封装的Timer对象,从其类文档中可以看到它的两种创建方式:timer和scheduledTimer。

self.timer = [NSTimer timerWithTimeInterval:2 repeats:true block:^(NSTimer * _Nonnull timer) 
    NSLog(@"timer");
}];

self.timer = [NSTimer timerWithTimeInterval:2 repeats:true block:^(NSTimer * _Nonnull timer) 
    NSLog(@"timer");
}];

[self.timer fire];
[self.timer invalidate];

timerWithTimeInterval创建的timer, 在fire后唤醒;
scheduledTimerWithTimeInterval创建的timer, 创建后立即唤醒;
timer在invalidate后停止。

dispatch

利用多线程GCD创建的Timer,精确度更高,也可以通过参数设置Timer首次执行时间。

 __block int count = 3;
 dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
 //通过start参数控制第一次执行的时间,DISPATCH_TIME_NOW表示立即执行
 dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
 dispatch_source_set_event_handler(timer, ^{
     NSLog(@"dispatch_source_set_timer start");
     NSLog(@"%zd", count);
     if (count == 0) {
         dispatch_source_cancel(timer);
     }
     count--;
 });
 NSLog(@"main queue");
 dispatch_resume(timer);
CADisplayLink

CADisplayLink是和iOS界面刷新效率同步执行,可以在1s内执行60次,执行效率最高。如果屏幕滑动时卡顿,可以用它来检测屏幕屏幕刷新频率。当然,不能在其执行方法中加载大量任务,否则手机内存会急剧增高。

@property (nonatomic, strong) CADisplayLink *link;
@property (nonatomic, strong) UILabel *label;
@property (nonatomic, assign) NSTimeInterval lastTime;
@property (nonatomic, assign) NSInteger count;

self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(tick:)];
[self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

- (void)tick: (CADisplayLink *)link {
    if (self.lastTime == 0) {
        self.lastTime = link.timestamp;
        return;
    }
    
    self.count++;
    NSLog(@"%f", link.timestamp);
    NSTimeInterval delta = link.timestamp - self.lastTime;
    if (delta < 1) return;
    self.lastTime = link.timestamp;
    float fps = _count / delta;
    self.label.text = [NSString stringWithFormat:@"%0f", fps];
    self.count = 0;
}
Tips:NSRunLoop

iOS应用执行的方式,采用了RunLoop的消息循环,简要来说启动后整个应用就进入一个死循环,应用中的所有事件(各种手势,交互功能(Target-Event)等)在死循环中被检测后加入到消息队列,然后不断执行。

每一线程中都有一个RunLoop,只不过子线程中的RunLoop默认关闭。通过[[NSRunLoop currentRunLoop] run]的方法可以唤醒子线程的RunLoop。

RunLoop中的模式有两种: kCFRunLoopDefaultMode和UITrackingRunLoopMode。kCFRunLoopDefaultMode也即是iOS开发文档中的NSDefaultRunLoopMode,NSRunLoopCommonModes是上述两种mode的组合。主线程的RunLoop在UIScrollView滑动时会切换成UITrackingRunLoopMode,如果将Timer添加到NSDefaultRunLoopMode,就会在滑动手势下停止执行。

关注和喜欢都是对我的鼓励和支持~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容