推薦使用GCD方式創(chuàng)建timer的原因赦拘,GCD是基于內(nèi)核的,會更加準(zhǔn)時,NSTimer和CADisplayLink依賴于RunLoop,如果Runloop的任務(wù)太繁重逾冬,可能會導(dǎo)致NSTimer不準(zhǔn)時
GCD的Timer創(chuàng)建
//stong修飾,強(qiáng)引用
@property (nonatomic,strong) dispatch_source_t timer;
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"begin");
// Do any additional setup after loading the view.
// 隊列
// dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
// dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_queue_t queue = dispatch_get_main_queue();
// 創(chuàng)建定時器
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 設(shè)置時間
// dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
// 設(shè)置時間祥诽,帶有延時幾秒后執(zhí)行的開啟定時器的參數(shù)
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 2NSEC_PER_SEC), 1NSEC_PER_SEC, 0);
// 設(shè)置回調(diào)
dispatch_source_set_event_handler(timer, ^{
// 上面設(shè)置為什么隊列譬圣,這個回調(diào)就在什么隊列里面執(zhí)行
NSLog(@"執(zhí)行定時器");
NSLog(@"%@",[NSThread currentThread]);
});
// 啟動定時器
dispatch_resume(timer);
// 設(shè)置timer為強(qiáng)引用的,否則不會執(zhí)行雄坪,出了函數(shù)調(diào)用棧厘熟,就銷毀了
self.timer = timer;
}
封裝一個timer對象
.h
@interface JGTimer : NSObject
//開始定時器的方法
+(NSString *)execTask:(void(^)(void))task start:(NSTimeInterval)start interval:(NSTimeInterval)interval repeats:(BOOL)repeats async:(BOOL)async;
//取消定時器
+(void)cancleTask:(NSString *)name;
@end
.m
import "JGTimer.h"
@implementation JGTimer
//使用字典來表示,任務(wù)的名字和timer一一對應(yīng)的關(guān)系,設(shè)置一個全局的字典
static NSMutableDictionary * timers_;
//使用信號量來解決多線程绳姨,同時操作字典的情況
dispatch_semaphore_t semaphore_ ;
// 使用initialize和單例初始化字典登澜,因?yàn)橹挥薪o這個類發(fā)送消息時候來回調(diào)用這個方法
+(void)initialize{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
timers_ = [NSMutableDictionary dictionary];
semaphore_ = dispatch_semaphore_create(1);
});
}
+(NSString *)execTask:(void(^)(void))task start:(NSTimeInterval)start interval:(NSTimeInterval)interval repeats:(BOOL)repeats async:(BOOL)async{
if (!task || start < 0 || (interval <= 0 && repeats)) {
return nil;
}
__weak typeof(self) weakSelf = self;
dispatch_queue_t queue = async ? dispatch_get_global_queue(0, 0) : dispatch_get_main_queue();
// 創(chuàng)建定時器
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 設(shè)置時間
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, start * NSEC_PER_SEC), interval * NSEC_PER_SEC, 0);
dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
// 設(shè)置任務(wù)的名字
NSString * name = [NSString stringWithFormat:@"%lu",(unsigned long)timers_.count];
// 給定時器增加強(qiáng)引用,并且是任務(wù)的名字和定時器一一對應(yīng)
timers_[name] = timer;
dispatch_semaphore_signal(semaphore_);
// 設(shè)置回調(diào)
dispatch_source_set_event_handler(timer, ^{
task();
// 如果取消這個任務(wù)飘庄,執(zhí)行一次就取消
if (!repeats) {
[weakSelf cancleTask:name];
}
});
// 啟動
dispatch_resume(timer);
return name;
}
+(void)cancleTask:(NSString *)name{
if (name.length == 0) {
return;
}
dispatch_source_t timer = timers_[name];
if (!timer) return;
// 如果信號的值為1的話脑蠕,會自動減1,然后執(zhí)行下面的代碼跪削,如果這個值為0谴仙,就會休眠等待,直到這個值大于0時候碾盐,才會喚醒和繼續(xù)執(zhí)行
dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
// 取消定時器
dispatch_source_cancel(timers_[name]);
// 從字典中刪除這個定時器晃跺,刪除強(qiáng)引用
[timers_ removeObjectForKey:name];
// 信號的值+1操作
dispatch_semaphore_signal(semaphore_);
}
使用封裝的定時器
-
(void)viewDidLoad {
[super viewDidLoad];
/*
NSLog(@"begin");
// 隊列
// dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
// dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_queue_t queue = dispatch_get_main_queue();
// 創(chuàng)建定時器
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 設(shè)置時間
// dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
// 設(shè)置時間,帶有延時幾秒后執(zhí)行的開啟定時器的參數(shù)
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 2NSEC_PER_SEC), 1NSEC_PER_SEC, 0);
// 設(shè)置回調(diào)
dispatch_source_set_event_handler(timer, ^{
// 上面設(shè)置為什么隊列廓旬,這個回調(diào)就在什么隊列里面執(zhí)行
NSLog(@"執(zhí)行定時器");
NSLog(@"%@",[NSThread currentThread]);
});
// 啟動定時器
dispatch_resume(timer);
// 設(shè)置timer為強(qiáng)引用的哼审,否則不會執(zhí)行,出了函數(shù)調(diào)用棧孕豹,就銷毀了
self.timer = timer;*/
// 封裝timer
NSLog(@"begin");
self.task = [JGTimer execTask:^{
NSLog(@"111");
} start:2 interval:1 repeats:YES async:YES];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// 取消定時器
[JGTimer cancleTask:self.task];
}