CADisplayLink
开启定时器
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(linkTest)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
结束定时器
[self.displayLink invalidate];
开启后定时器的调用频率跟屏幕刷新频率一样,依赖runloop不精准。
NSTimer
开启定时器
//开启1
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:proxy selector:@selector(timerTest) userInfo:nil repeats:YES];
//开启2
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
}];
//开启3
self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerTest) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
//开启4
self.timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
}];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
依赖runloop不精准。
结束定时器
[self.timer invalidate];
使用scheduledTimerWithTimeInterval创建的timer会被添加到当前线程的runloop的NSDefaultRunLoopMode模式下
-
CADisplayLink、NSTimer会对target产生强引用,如果target有对它们产生强引用,那么就会引发循环引用。
-
解决方法
- 使用block 这种只能用于timer
__weak typeof(self) weakSelf = self; self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) { __strong typeof(self) strongSelf = weakSelf; [strongSelf timeTest]; }];
- 使用代理对象
MyProxy2 *proxy = [MyProxy2 proxyWithTarget:self]; self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:proxy selector:@selector(test) userInfo:nil repeats:YES];
@interface MyProxy : NSObject +(instancetype)proxyWithTarget:(id)target; @property(nonatomic,weak)id target; @end @implementation MyProxy +(instancetype)proxyWithTarget:(id)target{ MyProxy *proxy = [[MyProxy alloc] init]; proxy.target = target; return proxy; } -(id)forwardingTargetForSelector:(SEL)aSelector{ return self.target; } @end
@interface MyProxy2 : NSProxy +(instancetype)proxyWithTarget:(id)target; @property(nonatomic,weak)id target; @end @implementation MyProxy2 +(instancetype)proxyWithTarget:(id)target{ MyProxy2 *proxy = [MyProxy2 alloc]; proxy.target = target; return proxy; } - (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel{ return [self.target methodSignatureForSelector:sel]; } - (void)forwardInvocation:(NSInvocation *)invocation{ [invocation invokeWithTarget:self.target]; } @end
NSProxy是专门用来做转发的类,效率更高,没有方法查找阶段,直接进入methodSignatureForSelector转发阶段。
GCD定时器
通过上面我们发现CADisplayLink、NSTimer不精准,要对计时器要求精准就得用到GCD. 开启定时器
-(void)test{
// dispatch_queue_t queue = dispatch_get_main_queue();
//创建队列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
//创建计时器
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//一定要用强引用保留住timer 要不启动不了
self.timer = timer;
//开始时间 可以去设置
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, 3.0 * NSEC_PER_SEC);
//设置开始时间,和间隔时间
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0);
//通过block回调
// dispatch_source_set_event_handler(timer, ^{
// NSLog(@"aa");
// });
//通过函数回调
dispatch_source_set_event_handler_f(timer,timerFire);
//启动定时器
dispatch_resume(timer);
}
void timerFire(void *param){
NSLog(@"bb,%@",[NSThread currentThread]);
}
结束定时器
dispatch_source_cancel(self.timer);
今天的文章OC经验-定时器分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/23323.html