NSTimer、CADisplayLink、dispatch_s

2020-10-27  本文已影响0人  Jean_Lina

NSTimer、CADisplayLink依赖Runloop,如果Runloop的任务过于繁重,可能导致NSTimer不准时。
GCD的定时器更准时,不依赖Runloop。
NSTimer:

@property (nonatomic, strong) NSTimer *timer;

#pragma mark 创建定时器
- (void)initTimer0 {
    //创建定时器1
    self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(updateTimer) userInfo:nil repeats:YES];
    
    //创建定时器2
    self.timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(updateTimer) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
}
#pragma mark 解决循环引用1
- (void)initTimer1 {    
    __weak typeof(self) weakSelf = self;
    //self强引用timer,timer强引用block,block弱引用self,进而timer弱引用self,打破循环引用
    self.timer = [NSTimer scheduledTimerWithTimeInterval:2 repeats:YES block:^(NSTimer * _Nonnull timer) {
        [weakSelf updateTimer];
    }];
}
#pragma mark 解决循环引用2
- (void)initTimer {
    //创建中间对象
    self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:[TimerProxy initWithTarget:self] selector:@selector(updateTimer) userInfo:nil repeats:YES];
}
- (void)updateTimer {
    NSLog(@"%s", __func__);
}
- (void)dealloc
{
    NSLog(@"%s", __func__);
    [self.timer invalidate];
}

CADisplayLink:

@property (nonatomic, strong) CADisplayLink *link;

- (void)initLink {
    //保证调用频率和屏幕的刷新帧率一致,60fps
    self.link = [CADisplayLink displayLinkWithTarget:[TimerProxy1 initWithTarget:self] selector:@selector(updateTimer)];
    //添加到runloop
    [self.link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)updateTimer {
    NSLog(@"%s", __func__);
}
- (void)dealloc
{
    NSLog(@"%s", __func__);
    [self.link invalidate];
}

NSProxy、NSObject都是基类。
NSProxy专门做代理的,在找不到方法时,不会从类、父类进行方法的查找,直接进行方法签名和方法调用。效率更高。
NSObject会在找不到方法时,进行消息查找、消息转发。

创建中间对象TimerProxy继承NSObject:

@interface TimerProxy : NSObject
//弱引用对象
@property (nonatomic, weak) TimerProxy *target;
+ (instancetype)initWithTarget:(id)target;
@end

@implementation TimerProxy
+ (instancetype)initWithTarget:(id)target {
    TimerProxy *proxy = [[TimerProxy alloc] init];
    proxy.target = target;
    return proxy;
}
#pragma mark 消息转发
- (id)forwardingTargetForSelector:(SEL)aSelector {
    return self.target;
}
@end

创建中间对象TimerProxy1继承NSProxy:

@interface TimerProxy1 : NSProxy
@property (nonatomic, weak) TimerProxy1 *target;
+ (instancetype)initWithTarget:(id)target;
@end

+ (instancetype)initWithTarget:(id)target {
    //NSProxy没有init方法
    TimerProxy1 *proxy = [TimerProxy1 alloc];
    proxy.target = target;
    return proxy;
}
#pragma mark 方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    return [self.target methodSignatureForSelector:sel];
}
#pragma mark 方法调用
- (void)forwardInvocation:(NSInvocation *)invocation {
    [invocation invokeWithTarget:self.target];
}

创建GCD定时器:dispatch_source_t,不依赖Runloop

@property (nonatomic, strong) dispatch_source_t timer;

#pragma mark 创建GCD定时器
- (void)initGCDTimer {
    NSLog(@"begin");
//    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    //设置事件处理
    dispatch_source_set_event_handler(self.timer, ^{
        NSLog(@"处理定时器任务%@", [NSThread currentThread]);
    });
    uint64_t start = 1;
    uint64_t interval = 2;
    dispatch_source_set_timer(self.timer, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(start * NSEC_PER_SEC)), (uint64_t)(interval * NSEC_PER_SEC), 0);
    //启动定时器
    dispatch_resume(self.timer);
}
上一篇 下一篇

猜你喜欢

热点阅读