在開發(fā)過程中,對(duì)于定時(shí)器相信大家都不陌生,在http://www.lxweimin.com/p/0194a0866872 這篇文章中,我有談過各種定時(shí)器的優(yōu)缺點(diǎn),這里就簡(jiǎn)單封裝一個(gè)實(shí)用的不依賴于RunLoop運(yùn)行模式的GCD定時(shí)器
-
首先GCD定時(shí)器本質(zhì)也是對(duì)象必須有一個(gè)強(qiáng)引用應(yīng)用著,不然就會(huì)被釋放,由于提供的是類方法,就定義一個(gè)全局靜態(tài)變量字典來保存timer對(duì)象
//存放timer對(duì)象
static NSMutableDictionary *timerDictionary;
//根據(jù)index來存儲(chǔ)不同的timer對(duì)象
static NSInteger timerIndex = 0;
- 提供了一下兩個(gè)類方法來初始化定時(shí)器,區(qū)別在于第一個(gè)初始化完成后自動(dòng)開啟定時(shí)器,第二個(gè)需要自己選擇開啟與否
//初始化定時(shí)器,默認(rèn)初始化完成后開啟
- (void)timerWithTimeInterval:(NSTimeInterval)timeInterval dispatchQueue:(dispatch_queue_t)dispatchQueue withBlock:(void(^)(XHR_dispatch_timer *))block;
//初始化定時(shí)器,需要手動(dòng)開啟
- (void)timerWithTimeInterval:(NSTimeInterval)timeInterval dispatchQueue:(dispatch_queue_t)dispatchQueue isOn:(BOOL)isOn withBlock:(void(^)(XHR_dispatch_timer *))block;
- 具體方法的實(shí)現(xiàn)如下
//初始化定時(shí)器
- (void)timerWithTimeInterval:(NSTimeInterval)timeInterval dispatchQueue:(dispatch_queue_t)dispatchQueue withBlock:(void (^)())block
{
//默認(rèn)方法自動(dòng)開啟定時(shí)器
[self timerWithTimeInterval:timeInterval dispatchQueue:dispatchQueue isOn:YES withBlock:block];
}
-
(void)timerWithTimeInterval:(NSTimeInterval)timeInterval dispatchQueue:(dispatch_queue_t)dispatchQueue isOn:(BOOL)isOn withBlock:(void (^)(XHR_dispatch_timer *))block
{
XHR_dispatch_timer *timer = [[XHR_dispatch_timer alloc]initWithTimeInterval:timeInterval dispatchQueue:dispatchQueue withBlock:block];[self.timerDictionary setObject:timer forKey:[NSString stringWithFormat:@"timerIndex_%ld",timerIndex++]];
//根據(jù)設(shè)置是否需要在初始化完成后開啟
if (isOn) {
timer.timerStatus = XHR_dispatch_timerStatusRuning;
}
}
- 那么解釋一下這里的XHR_dispatch_timer,它是定義在XHRTimer這個(gè)單例內(nèi)的一個(gè)私有類,是用來管理每一個(gè)timer對(duì)象的,以便在創(chuàng)建不同的timer對(duì)象執(zhí)行不同的任務(wù),并且定義了一個(gè)定時(shí)器狀態(tài)枚舉來標(biāo)記運(yùn)作狀態(tài),通過調(diào)整運(yùn)作狀態(tài)就可以控制定時(shí)器的開啟、暫停、取消等操作,也避免了多次開啟、暫停、取消而引起的bug,具體實(shí)現(xiàn)如下
- (instancetype)initWithTimeInterval:(NSTimeInterval)timeInterval dispatchQueue:(dispatch_queue_t)dispatchQueue withBlock:(void(^)(XHR_dispatch_timer *))block
{
if (self = [super init]) {
//timer本質(zhì)也是對(duì)象必須有強(qiáng)應(yīng)用引用,不然就會(huì)被釋放
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatchQueue);
//設(shè)置開始時(shí)間和時(shí)間間隔
dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, timeInterval * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
//設(shè)置回調(diào)時(shí)間
dispatch_source_set_event_handler(self.timer, ^{
block(self);
});
self.timerStatus = XHR_dispatch_timerStatusSuspend;
}
return self;
} - (void)setTimerStatus:(XHR_dispatch_timerStatus)timerStatus
{
if (!self.timer) return;
if (timerStatus == XHR_dispatch_timerStatusSuspend && _timerStatus != XHR_dispatch_timerStatusSuspend) {
dispatch_suspend(self.timer);
}
else if (timerStatus == XHR_dispatch_timerStatusRuning && _timerStatus == XHR_dispatch_timerStatusSuspend)
{
dispatch_resume(self.timer);
}
else if(timerStatus == XHR_dispatch_timerStatusCanceled && _timerStatus != XHR_dispatch_timerStatusCanceled)
{
dispatch_cancel(self.timer);
self.timer = nil;
}
_timerStatus = timerStatus;
}
- 暫停定時(shí)器的方法
//暫停定時(shí)器
- (void)suspend:(XHR_dispatch_timer *)timer
{
if (timer) {
timer.timerStatus = XHR_dispatch_timerStatusSuspend;
}
} - (void)suspendAllTimer
{
[self.timerDictionary enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, XHR_dispatch_timer *_Nonnull obj, BOOL * _Nonnull stop) {
obj.timerStatus = XHR_dispatch_timerStatusSuspend;
}];
}
- 手動(dòng)開啟/繼續(xù) 定時(shí)器的方法
//手動(dòng)開啟/繼續(xù) 定時(shí)器
- (void)resume:(XHR_dispatch_timer *)timer
{
if (timer) {
timer.timerStatus = XHR_dispatch_timerStatusRuning;
}
} - (void)resumeAllTimer
{
[self.timerDictionary enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, XHR_dispatch_timer *_Nonnull obj, BOOL * _Nonnull stop) {
obj.timerStatus = XHR_dispatch_timerStatusRuning;
}];
}
- 取消定時(shí)器
//取消定時(shí)器
//取消定時(shí)器
- (void)cancel:(XHR_dispatch_timer *)timer
{
if (timer) {
timer.timerStatus = XHR_dispatch_timerStatusCanceled;
}
[self.timerDictionary enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
if ([obj isEqual:timer]) {
[self.timerDictionary removeObjectForKey:key];
return;
}
}];
} - (void)cancelAllTimer
{
[self.timerDictionary enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, XHR_dispatch_timer *_Nonnull obj, BOOL * _Nonnull stop) {
obj.timerStatus = XHR_dispatch_timerStatusCanceled;
}];
[self.timerDictionary removeAllObjects];
}
注:
- 調(diào)用方法和NSTimer類似,使用類方法,需要執(zhí)行的代碼直接寫在方法的block中,非常方便.需要注意的是,如果取消了定時(shí)器,如果想重新開啟就需要重新初始化,不然就會(huì)崩潰。
- bolock傳出去的參數(shù)是為了供外部解決循環(huán)應(yīng)用問題的
作者:胥鴻儒
demo地址:https://github.com/xuhongru/GCDTimer