iOS三种定时器
一、 NSTimer
注意点:timerWithTimeInterval: target: selector: userInfo: repeats:
凡是timerWithTimeInterval
开头的都是需要手动添加到RunLoop
中。scheduledTimerWithTimeInterval
开头的方法内部自动添加到RunLoop
中。
//这里的self换成weakSelf 也不行,里面找到target的地址再强引用
NSTimer * timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(test) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
如果添加到子线程中:
-
保证
RunLoop
创建并且Run起来了 -
timer需要添加到RunLoop中
[loop addTimer:timer forMode:NSRunLoopCommonModes];
优点: 方便使用
缺点: 计时不精确,容易造成循环引用
设置的TimeInterval
是最小时间间隔
不管是一次性的还是周期性的timer的实际触发事件的时间,都会与所加入的RunLoop和RunLoop Mode有关,如果此RunLoop正在执行一个耗时操作,timer就会被延时出发。重复性的timer遇到这种情况,如果延迟超过了一个周期,则会在延时结束后立刻执行,并按照之前指定的周期继续执行。
RunLoop强引用Timer,timer在强引用target,解决强引用:
- 利用NSProxy,消息转发
- 使用新的的API:
timerWithTimeInterval: repeats: block:
(只对iOS10 以后)
二、CADisplayLink
CADisplayLink:根据刷新频率来计算时间间隔
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(test)];
[link setPreferredFramesPerSecond:20];
[link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
注意:
setPreferredFramesPerSecond
表示每秒执行的次数;- 必须添加到
RunLoop
中
优点: 只要设备屏幕刷新频率保持在60fps,那么其触发时间上是最准确的。
缺点: 由于依托于屏幕刷新频率,如果CPU任务过重,那么会影响屏幕刷新,触发事件也会受到相应影响。
三、dispatch_source_t
注意:
dispatch_source_t _timer;
全局的,不然创建完了执行一次就销毁了
dispatch_source_t _timer;
void testGCDSourceTimer() {
dispatch_queue_t queue = dispatch_queue_create("com.ob", DISPATCH_QUEUE_CONCURRENT);
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC, 1 * NSEC_PER_SEC);
dispatch_source_set_event_handler(_timer, ^{
NSLog(@"test---");
});
dispatch_resume(_timer);
}
//开始
dispatch_resume(_timer);
//暂停
dispatch_suspend(_timer);
//销毁
dispatch_source_cancel(_timer);
优点: 非常精确,要想达到百分比精确需要单独拥有一个队列,只处理time相关的任务,并且time的回调处理时长不能操过设置的时间间隔。
缺点: 不受RunLoop的影响,需要注意内存管理