不需要手动释放的IOS定时器

2019-01-05  本文已影响0人  夏末秋刀鱼

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可以确保系统渲染每一帧的时候我们的方法都被调用,从而保证了动画的流畅性

上一篇下一篇

猜你喜欢

热点阅读