美文网首页Objective-C
iOS:三种定时器

iOS:三种定时器

作者: 码小菜 | 来源:发表于2020-05-03 17:33 被阅读0次
    风景

    目录
    一,NSTimer
    二,CADisplayLink
    三,dispatch_source_timer

    一,NSTimer

    1,基本使用

    • timerWithTimeInterval:
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSTimer *timer = [NSTimer timerWithTimeInterval:1.0
                                                repeats:YES
                                                  block:^(NSTimer * _Nonnull timer) {
            NSLog(@"timer running");
        }];
        [[NSRunLoop currentRunLoop] addTimer:timer
                                     forMode:NSDefaultRunLoopMode];
    }
    
    // 打印
    07:21:30.266493+0800 Demo[10449:9624199] timer running
    07:21:31.266367+0800 Demo[10449:9624199] timer running
    07:21:32.266795+0800 Demo[10449:9624199] timer running
    
    • scheduledTimerWithTimeInterval:
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // 自动添加到runloop的NSDefaultRunLoopMode中
        [NSTimer scheduledTimerWithTimeInterval:1.0
                                        repeats:YES
                                          block:^(NSTimer * _Nonnull timer) {
            NSLog(@"timer running");
        }];
    }
    
    // 打印
    07:24:10.249589+0800 Demo[10584:9626453] timer running
    07:24:11.250144+0800 Demo[10584:9626453] timer running
    07:24:12.250318+0800 Demo[10584:9626453] timer running
    
    • initWithFireDate:
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSLog(@"begin");
        NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:3.0]
                                                  interval:1.0
                                                   repeats:YES
                                                     block:^(NSTimer * _Nonnull timer) {
            NSLog(@"timer running");
        }];
        [[NSRunLoop currentRunLoop] addTimer:timer
                                     forMode:NSDefaultRunLoopMode];
    }
    
    // 打印
    07:32:16.943407+0800 Demo[10738:9632602] begin
    07:32:19.944573+0800 Demo[10738:9632602] timer running
    07:32:20.944960+0800 Demo[10738:9632602] timer running
    07:32:21.944652+0800 Demo[10738:9632602] timer running
    

    2,解决循环引用

    /**
     self强引用timer,timer强引用proxy,proxy弱引用self
     */
    
    // YJProxy.h
    @interface YJProxy : NSObject
    + (instancetype)proxyWithTarget:(id)target;
    @end
    
    // YJProxy.m
    @interface YJProxy ()
    @property (nonatomic, weak) id target; // 弱引用
    @end
    
    @implementation YJProxy
    + (instancetype)proxyWithTarget:(id)target {
        YJProxy *proxy = [[YJProxy alloc] init];
        proxy.target = target;
        return proxy;
    }
    - (id)forwardingTargetForSelector:(SEL)aSelector { // 消息转发
        return self.target;
    }
    @end
    
    // ViewController
    @interface ViewController ()
    @property (nonatomic, strong) NSTimer *timer;
    @end
    
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                      target:[YJProxy proxyWithTarget:self]
                                                    selector:@selector(timerTask)
                                                    userInfo:nil
                                                     repeats:YES];
    }
    - (void)timerTask {
        NSLog(@"%s", __func__);
    }
    - (void)dealloc {
        NSLog(@"%s", __func__);
        [self.timer invalidate];
    }
    @end
    
    // 打印
    07:56:14.897620+0800 Demo[11187:9646035] -[ViewController timerTask]
    07:56:15.897446+0800 Demo[11187:9646035] -[ViewController timerTask]
    07:56:16.898022+0800 Demo[11187:9646035] -[ViewController timerTask]
    07:56:17.860300+0800 Demo[11187:9646035] -[ViewController dealloc]
    

    3,NSProxy

    • 使用
    @interface YJProxy : NSProxy
    + (instancetype)proxyWithTarget:(id)target;
    @end
    
    @interface YJProxy ()
    @property (nonatomic, weak) id target;
    @end
    
    @implementation YJProxy
    + (instancetype)proxyWithTarget:(id)target {
        // NSProxy没有init方法
        YJProxy *proxy = [YJProxy alloc];
        proxy.target = target;
        return proxy;
    }
    // 消息转发
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
        return [self.target methodSignatureForSelector:sel];
    }
    - (void)forwardInvocation:(NSInvocation *)invocation {
        [invocation invokeWithTarget:self.target];
    }
    @end
    
    • 说明

    1>它跟NSObject是同一级别的

    2>它专用于消息转发

    3>用它做代理对象效率更高,因为它是直接执行消息转发的,而NSObject需要先执行消息发送和动态方法解析

    二,CADisplayLink

    1,使用

    @interface ViewController ()
    @property (nonatomic, strong) CADisplayLink *link;
    @end
    
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.link = [CADisplayLink displayLinkWithTarget:[YJProxy proxyWithTarget:self]
                                                selector:@selector(linkTask)];
        // 设置每秒执行1次
        self.link.preferredFramesPerSecond = 1;
        [self.link addToRunLoop:[NSRunLoop currentRunLoop]
                        forMode:NSDefaultRunLoopMode];
    }
    - (void)linkTask {
        NSLog(@"%s", __func__);
        // 下一次执行的时间 - 当前时间
        NSLog(@"%f", self.link.targetTimestamp - self.link.timestamp);
        // 两帧之间的时间间隔
        NSLog(@"%f", self.link.duration);
    }
    - (void)dealloc {
        NSLog(@"%s", __func__);
        [self.link invalidate];
    }
    @end
    
    // 打印
    13:26:37.176374+0800 Demo[15813:9765865] -[ViewController linkTask]
    13:26:37.176581+0800 Demo[15813:9765865] 1.000000
    13:26:37.176682+0800 Demo[15813:9765865] 0.016667
    13:26:38.172891+0800 Demo[15813:9765865] -[ViewController linkTask]
    13:26:38.173096+0800 Demo[15813:9765865] 1.000000
    13:26:38.173237+0800 Demo[15813:9765865] 0.016667
    13:26:39.173083+0800 Demo[15813:9765865] -[ViewController linkTask]
    13:26:39.173282+0800 Demo[15813:9765865] 1.000000
    13:26:39.173442+0800 Demo[15813:9765865] 0.016667
    13:26:39.207185+0800 Demo[15813:9765865] -[ViewController dealloc]
    

    2,说明

    • 它是一个与屏幕刷新相关的定时器

    • 屏幕刷新频率是60FPS,所以它默认每秒执行60次

    • duration是按照60FPS来计算的(1 / 60 = 0.016667)

    三,dispatch_source_timer

    1,使用

    @interface ViewController ()
    @property (nonatomic, strong) dispatch_source_t timer;
    @end
    
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        // 创建定时器并设置执行任务的队列
        self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        // 每1秒执行一次任务并允许有1秒的误差
        dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 1.0 * NSEC_PER_SEC);
        
        // 定时器任务
        dispatch_source_set_event_handler(self.timer, ^{
            NSLog(@"timer running---%@", [NSThread currentThread]);
        });
        
        // 定时器被取消的回调
        dispatch_source_set_cancel_handler(self.timer, ^{
            NSLog(@"timer cancelled---%@", [NSThread currentThread]);
        });
        
        // 启动定时器
        dispatch_resume(self.timer);
    }
    - (void)dealloc {
        NSLog(@"%s", __func__);
        // 取消定时器
        dispatch_source_cancel(self.timer);
    }
    @end
    
    // 打印
    15:15:24.073246+0800 Demo[17534:9809826] timer running---<NSThread: 0x6000035f2bc0>{number = 8, name = (null)}
    15:15:25.073340+0800 Demo[17534:9809827] timer running---<NSThread: 0x6000035c5000>{number = 8, name = (null)}
    15:15:26.155698+0800 Demo[17534:9809827] timer running---<NSThread: 0x6000035c5000>{number = 6, name = (null)}
    15:15:27.247158+0800 Demo[17534:9809775] -[ViewController dealloc]
    15:15:27.247717+0800 Demo[17534:9809827] timer cancelled---<NSThread: 0x6000035c5000>{number = 5, name = (null)}
    

    2,说明

    • 定时器在运行或取消状态下,调用dispatch_resume函数会crash

    • 它不受runloop的影响,所以比NSTimerCADisplayLink都准时

    相关文章

      网友评论

        本文标题:iOS:三种定时器

        本文链接:https://www.haomeiwen.com/subject/hihfghtx.html