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);
}