iOS:三種定時(shí)器

目錄
一,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];
    
    // 自動(dòng)添加到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,解決循環(huán)引用

/**
 self強(qiáng)引用timer,timer強(qiáng)引用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 { // 消息轉(zhuǎn)發(fā)
    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;
}
// 消息轉(zhuǎn)發(fā)
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
    [invocation invokeWithTarget:self.target];
}
@end
  • 說明

1>它跟NSObject是同一級(jí)別的

2>它專用于消息轉(zhuǎn)發(fā)

3>用它做代理對(duì)象效率更高,因?yàn)樗侵苯訄?zhí)行消息轉(zhuǎn)發(fā)的,而NSObject需要先執(zhí)行消息發(fā)送和動(dòng)態(tài)方法解析

二,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)];
    // 設(shè)置每秒執(zhí)行1次
    self.link.preferredFramesPerSecond = 1;
    [self.link addToRunLoop:[NSRunLoop currentRunLoop]
                    forMode:NSDefaultRunLoopMode];
}
- (void)linkTask {
    NSLog(@"%s", __func__);
    // 下一次執(zhí)行的時(shí)間 - 當(dāng)前時(shí)間
    NSLog(@"%f", self.link.targetTimestamp - self.link.timestamp);
    // 兩幀之間的時(shí)間間隔
    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,說明

  • 它是一個(gè)與屏幕刷新相關(guān)的定時(shí)器

  • 屏幕刷新頻率是60FPS,所以它默認(rèn)每秒執(zhí)行60次

  • duration是按照60FPS來計(jì)算的(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);
    // 創(chuàng)建定時(shí)器并設(shè)置執(zhí)行任務(wù)的隊(duì)列
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    // 每1秒執(zhí)行一次任務(wù)并允許有1秒的誤差
    dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 1.0 * NSEC_PER_SEC);
    
    // 定時(shí)器任務(wù)
    dispatch_source_set_event_handler(self.timer, ^{
        NSLog(@"timer running---%@", [NSThread currentThread]);
    });
    
    // 定時(shí)器被取消的回調(diào)
    dispatch_source_set_cancel_handler(self.timer, ^{
        NSLog(@"timer cancelled---%@", [NSThread currentThread]);
    });
    
    // 啟動(dòng)定時(shí)器
    dispatch_resume(self.timer);
}
- (void)dealloc {
    NSLog(@"%s", __func__);
    // 取消定時(shí)器
    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,封裝

// YJTimer.h
@interface YJTimer : NSObject
- (instancetype)initWithInterval:(NSTimeInterval)interval
                         repeats:(BOOL)repeats
                           async:(BOOL)async
                           block:(void(^)(YJTimer *timer))block;
- (void)start;
- (void)cancel;
@end

// YJTimer.m
@interface YJTimer ()
@property (nonatomic, strong) dispatch_source_t timer;
@end

@implementation YJTimer
- (instancetype)initWithInterval:(NSTimeInterval)interval
                         repeats:(BOOL)repeats
                           async:(BOOL)async
                           block:(void(^)(YJTimer *timer))block {
    if (self = [super init]) {
        dispatch_queue_t queue;
        if (async) {
            queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        } else {
            queue = dispatch_get_main_queue();
        }

        self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, interval * NSEC_PER_SEC, 0.0 * NSEC_PER_SEC);
        
        __weak typeof(self) weakSelf = self;
        dispatch_source_set_event_handler(self.timer, ^{
            if (block) {
                block(weakSelf);
            }
            if (!repeats) {
                [weakSelf cancel];
            }
        });
    }
    return self;
}
- (void)start {
    dispatch_resume(self.timer);
}
- (void)cancel {
    dispatch_source_cancel(self.timer);
}
@end

// ViewController
@interface ViewController ()
@property (nonatomic, strong) YJTimer *timer;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.timer = [[YJTimer alloc] initWithInterval:1.0
                                           repeats:YES
                                             async:YES
                                             block:^(YJTimer * _Nonnull timer) {
        NSLog(@"timer running---%@", [NSThread currentThread]);
    }];
    [self.timer start];
}
- (void)dealloc {
    [self.timer cancel];
}
@end

// 打印
09:50:01.948312+0800 Demo[24436:9961956] timer running---<NSThread: 0x6000026a8140>{number = 8, name = (null)}
09:50:02.949507+0800 Demo[24436:9961960] timer running---<NSThread: 0x6000026aed40>{number = 9, name = (null)}
09:50:03.949519+0800 Demo[24436:9961960] timer running---<NSThread: 0x6000026aed40>{number = 9, name = (null)}

3,說明

  • 定時(shí)器在運(yùn)行或取消狀態(tài)下,調(diào)用dispatch_resume函數(shù)會(huì)crash

  • 它不受runloop的影響,所以比NSTimerCADisplayLink都準(zhǔn)時(shí)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容