不需要手动释放的IOS定时器
1.GCD
优点:
调用 dispatch_source_cancel(timer); 就会将 timer 对象销毁,唯一要考虑的就是 timer 的结束时机;即使你不主动释放timer, 也不会造成循环引用哦 O(∩_∩)O~,weaktarget释放时,定时器也会自己dispatch_source_cancel(),不需要像nstimer每次自己手动释放
封装一个GCD定时器,原文:https://blog.csdn.net/zxw_xzr/article/details/68068368
/**
开启一个定时器
@param target 定时器持有者
@param timeInterval 执行间隔时间
@param handler 重复执行事件
*/
void dispatchTimer(id target, double timeInterval,void (^handler)(dispatch_source_t timer))
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timer =dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,0, 0, queue);
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), (uint64_t)(timeInterval *NSEC_PER_SEC), 0);
// 设置回调
__weak __typeof(target) weaktarget = target;
dispatch_source_set_event_handler(timer, ^{
if (!weaktarget) {
dispatch_source_cancel(timer);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
if (handler) handler(timer);
});
}
});
// 启动定时器
dispatch_resume(timer);
}
---------------------
通过观察代码,我们可以发现GCD定时器实际上是使用了dispatch源(dispatch source),dispatch源监听系统内核对象并处理。dispatch类似生产者消费者模式,通过监听系统内核对象,在生产者生产数据后自动通知相应的dispatch队列执行,后者充当消费者。通过系统级调用,更加精准。
补充其他定时器方法:
NSTimer
一般常用定时器为NSTimer
1.只创建,需要手动加入RunLoop才会开始
// 创建NSTimer对象
NSTimer *timer = [NSTimer timerWithTimeInterval:3 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
// 加入RunLoop中
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
2.创建自动加入到NSDefaultRunLoopMode
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(action:) userInfo:nil repeats:YES];
注意点:
1.需要释放计时器,需要先销毁
// 停止定时器
[timer invalidate];
timer = nil;
2.UIScrollView 滑动时执行的是 UITrackingRunLoopMode,NSDefaultRunLoopMode被挂起,会导致定时器失效,等恢复为滑动结束时才恢复定时器。
解决:
//加入NSRunLoopCommonModes
[[NSRunLoop mainRunLoop] addTimer:timer forMode: NSRunLoopCommonModes];
3.NSTimer不是绝对准确的,如果此RunLoop正在执行一个连续性的运算,timer就会被延时出发。
CADisplayLink
(暂时没用过,暂且记下,主要是根据屏幕每次刷新调用)
CADisplayLink对象是一个和屏幕刷新率同步的定时器对象。每当屏幕显示内容刷新结束的时候,runloop就会向CADisplayLink指定的target发送一次指定的selector消息, CADisplayLink类对应的 selector 就会被调用一次。
从原理上可以看出,CADisplayLink适合做界面的不停重绘,比如视频播放的时候需要不停地获取下一帧用于界面渲染,或者做动画。
使用方法:
@property (nonatomic, strong) CADisplayLink *displayLink;
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
// 每隔1帧调用一次
self.displayLink.frameInterval = 1;
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
释放方法
[self.displayLink invalidate];
self.displayLink = nil;
调用间隔时间为
self.displayLink .frameInterval * self.displayLink.duration
注意点:
duration为只读属性,正常情况下IOS设备刷新为一秒钟60次,但是如果CPU过于繁忙,无法保证屏幕60次/秒的刷新率,就会导致跳过若干次调用回调方法的机会。所以CADisplayLink可以确保系统渲染每一帧的时候我们的方法都被调用,从而保证了动画的流畅性。