1.iOS 中定时器的解决方案?
(1).CADisplayLink
使用简单,代码简洁,和屏幕刷帧频率相同,使用时需要注意循环引用问题,由于依赖 RunLoop 来实现定时功能.所以需要手动添加到 RunLoop 中.
(2).NSTimer
NSTimer 是我们项目中经常使用到的定时器的一种方案,同样也需要注意循环引用问题, NSTimer 和CADisplayLink一样,需要依赖 RunLopp,所以也需要手动添加到 RunLoop 中,需要注意的是,使用 NSTimer 的类方法scheduledTimerWithTimeInterval:创建 NSTimer 时,会自动添加到当前的 RunLoop 中.
(3).GCD
C语言的一套实现定时任务的方案,代码相对较多,使用较繁琐
*使用CADisplayLink和NSTimer过程中出现的循环引用的问题可以通过NSProxy来解决
*相对于CADisplayLink和NSTimer, GCD不依赖于 RunLoop, 和系统内核直接挂钩,所以具有更高的准时性,万一 RunLoop 处理的事情很多,就会造成CADisplayLink和NSTimer的不准确.
2.使用GCD简单自定义的定时器
下面是使用GCD 实现的定时器,可以直接拿来用.
#import
@interfaceMRTimer :NSObject
+(NSString*)doTask:(void(^)(void))task
start:(NSTimeInterval)start
interval:(NSTimeInterval)interval
repeat:(BOOL)repeat
async:(BOOL)async;
+(NSString*)doTask:(id)target
selector:(SEL)selector
start:(NSTimeInterval)start
interval:(NSTimeInterval)interval
repeat:(BOOL)repeat
async:(BOOL)async;
+(void)cancelTask:(NSString*)name;
@end
#import "MRTimer.h"
@implementation MRTimer
static NSMutableDictionary *timers_;
dispatch_semaphore_t semaphore_;
+(void)initialize{
staticdispatch_once_tonceToken;
dispatch_once(&onceToken, ^{
timers_=@{}.mutableCopy;
semaphore_ = dispatch_semaphore_create(1);
});
}
+(NSString*)doTask:(void(^)(void))task
start:(NSTimeInterval)start
interval:(NSTimeInterval)interval
repeat:(BOOL)repeat
async:(BOOL)async{
if(!task || start <0|| (interval <=0&& repeat))returnnil;
dispatch_queue_tqueue = async
?dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
:dispatch_get_main_queue();
dispatch_source_ttimer =dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,0,0, queue);
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, start * NSEC_PER_SEC, interval * NSEC_PER_SEC);
dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
NSString*name = [NSStringstringWithFormat:@"%lu",(unsignedlong)timers_.count];
timers_[name] = timer;
dispatch_semaphore_signal(semaphore_);
dispatch_source_set_event_handler(timer, ^{
task();
if(!repeat) {
dispatch_source_cancel(timer);
}
});
dispatch_resume(timer);
returnname;
}
+(NSString*)doTask:(id)target
selector:(SEL)selector
start:(NSTimeInterval)start
interval:(NSTimeInterval)interval
repeat:(BOOL)repeat
async:(BOOL)async{
if(!target || !selector)returnnil;
return [self doTask:^{
if([targetrespondsToSelector:selector]) [targetperformSelector:selector];
}start:startinterval:intervalrepeat:repeatasync:async];
}
+(void)cancelTask:(NSString*)name{
if(name.length==0)return;
dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
dispatch_source_ttimer =timers_[name];
if(!timer)return;
dispatch_source_cancel(timer);
[timers_ removeObjectForKey:name];
dispatch_semaphore_signal(semaphore_);
}
@end