NSTimer
概述
NSTimer
是Foundation
结构中的一个类,用于创立守时器,能够在指定的时刻距离内履行指定的使命。NSTimer
以RunLoop
的办法作业,能够将其加入RunLoop
的特定形式中,然后守时器能够在指定的时刻距离内持续作业
调用办法
办法1
// 以该办法创立的守时器以默认办法增加到当前线程runloop中,无需手动增加
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"%s, %d", __func__, __LINE__);
}];
// 之所以指定该守时器地点的Mode为NSRunLoopCommonModes,是为了确保守时器能够在不同的RunLoop Mode下正常运行
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// 中止守时器
[timer invalidate];
办法2
// 以该办法创立的守时器需求手动增加到RunLoop才干正常履行
NSTimer *timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(test:) userInfo:@"2" repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
-(void)test: (NSTimer *)content {
NSLog(@"%s, %d, %@", __func__, __LINE__, [content userInfo]);
}
// 中止守时器
[timer invalidate];
运用圈套
-
NSTimer
的作业办法是基于RunLoop
的,因而需求将其加入RunLoop
才干收效。假如不加入RunLoop
,守时器将无法发动 - 在运用
NSTimer
时要留意循环引证问题,应该运用弱引证或者block
来防止循环引证,也可经过NSProxy
创立一个临时Target - 在多线程中运用
NSTimer
,需求留意线程安全的问题,能够考虑运用GCD
守时器或者NSRunLoop
的performSelector:afterDelay:
办法等代替 - 当守时器不再运用时,需求将其从
RunLoop
中移除,防止内存走漏和无用功耗,且其创立与吊销必须在同一个线程操作,不能跨越线程操作 -
NSTimer
依赖于Runloop
,假如Runloop
的使命过于深重,可能会导致NStimer
不按时
CADisplayLink
概述
CADisplayLink
是Core Animation
结构中的一个类,用于创立一个与显现器刷新频率相同的计时器,如每秒 60 次(屏幕刷新率为 60Hz)调用一次指定办法。CADisplayLink
能够直接和Core Animation
进行结合,用于完成动画烘托、图形制作等操作,并且能够在多个RunLoop Modes
中履行,非常灵敏。
运用场景
- 实时数据展示:比如在股票行情中,实时制作股票价格图表
- 游戏开发:比如用于精灵动画的接连播映
- 视频录制:实时处理视频帧数据,完成视频的录制和处理
- 音频波形分析:实时制作音频波形图,显现音频数据变化
调用办法
// 需求将CADisplayLink目标增加到runLoop中,selector就能被周期性调用
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(test:)];
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
运用圈套
-
CADisplayLink
的使命办法需求在RunLoop
中运行,因而需求将其加入指定的RunLoop Mode
中 -
CADisplayLink
显现器刷新率为 60Hz,因而它的使命办法最好不要履行过于耗时的操作,以防止影响界面流畅性 - 在运用
CADisplayLink
时要留意循环引证问题,应该运用弱引证或者block
来防止循环引证 - 当
CADisplayLink
不再运用时,需求手动中止它的作业,防止内存走漏和无用功耗
GCD
+ (NSString *)executeTask:(task)task
start:(NSTimeInterval)start
interval:(NSTimeInterval)interval
repeats:(BOOL)repeats
async:(BOOL)async {
if (!task || start < 0 || (interval <= 0 && repeats) ) return nil;
// 行列
dispatch_queue_t queue = async ? dispatch_get_global_queue(0, 0) : dispatch_get_main_queue();
// 创立守时器
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 设置时刻
// 精准度:一般为0,假如对守时操作要求不精确,只要在一段时刻内履行就能够,那么能够把精准度设置的大一点,例如10,这样会进步程序功能
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, interval * NSEC_PER_SEC, 0);
// 加锁
dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
// 守时器唯一标识
NSString *name = [NSString stringWithFormat:@"%ld", timers_.count];
// 存放到字典中
timers_[name] = timer;
// 解锁
dispatch_semaphore_signal(semaphore_);
// 设置回调
dispatch_source_set_event_handler(timer, ^{
task();
// 不重复的使命
if (!repeats) {
[self cancelTask:name];
}
});
// 发动守时器
dispatch_resume(timer);
return name;
}
长处
GCD守时器实际上是运用了dispatch源(dispatch source),dispatch源监听系统内核目标并处理。dispatch相似出产者消费者形式,经过监听系统内核目标,在出产者出产数据后主动告诉相应的dispatch行列履行,后者充当消费者。经过系统级调用,更加精准