#import "GCDTimer.h"
@interface GCDTimer ()
@property (nonatomic, strong) dispatch_source_t timer;
@end
@implementation ?GCDTimer
- (void)runTimer?
? ? self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
? ? dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, 0), (uint64_t)(3*NSEC_PER_SEC), 0);
? ? dispatch_source_set_event_handler(self.timer, ^{
? ? ? ? NSLog(@"dispatch");
? ? });
? ? dispatch_resume(self.timer);
}
- (void)dealloc{
? ? dispatch_source_cancel(_timer);
}
@end
dispatch_resume()
激活源對(duì)象。新創(chuàng)建的timer必須激活才會(huì)執(zhí)行。
dispatch_suspend()
暫停源對(duì)象。dispatch_suspend 暫停隊(duì)列并不意味著當(dāng)前執(zhí)行的 block 暫停,調(diào)用 dispatch_suspend 暫停一個(gè)隊(duì)列,并不意味著暫停當(dāng)前正在執(zhí)行的 block,而是 block 可以執(zhí)行完,但是接下來的 block 會(huì)被暫停,直到 dispatch_resume 被調(diào)用。
dispatch_source_cancel()
銷毀定時(shí)器。dispatch_source_cancel 則是真正意義上的取消?timer。被取消之后如果想再次執(zhí)行?timer,只能重新創(chuàng)建新的?timer。這個(gè)過程類似于對(duì) NSTimer 執(zhí)行 invalidate。
需要注意的是,dispatch_source_t? 一定要被設(shè)置為成員變量,否則將會(huì)立即被釋放。
注意:暫停(dispatch_suspend)的timer,不能被釋放的,會(huì)引起崩潰。
Calls to dispatch_suspend() must be balanced with calls to dispatch_resume().
dispatch_suspend 和 dispatch_resume 應(yīng)該是成對(duì)出現(xiàn)的。兩者分別會(huì)減少和增加 dispatch 對(duì)象的暫停計(jì)數(shù),但是沒有 API 獲取當(dāng)前是暫停還是執(zhí)行狀態(tài),所以需要自己記錄。你調(diào)用了suspend(暫停)幾次,你想resume(恢復(fù))的話,就必須要remuse(恢復(fù))幾次,才能繼續(xù)運(yùn)行。
所以建議控制器添加一個(gè)標(biāo)識(shí)符,記錄源是否處于暫停狀態(tài),在dealloc事件中判斷當(dāng)前源是否被暫停,如果被暫停,則resume,即可解決內(nèi)存泄漏問題。
但是還有不一般的情況,如果暫停的代碼加到 dispatch_source_set_event_handler 的 block 中,并不會(huì)發(fā)生崩潰,但是這個(gè)時(shí)候頁面會(huì)無法釋放造成內(nèi)存泄漏。
dispatch_source_set_event_handler(timer, ^() {
? dispatch_suspend(self.timer);
});
其他注意事項(xiàng):
1.但remuse(恢復(fù))的狀態(tài)下,如果再進(jìn)行一次resume(恢復(fù))就會(huì)crash,所以要注冊(cè)一個(gè)BOOL值的狀態(tài)進(jìn)行記錄,防止多次suspend和resume引起閃退。
2.在suspend(暫停)的狀態(tài)下,如果你設(shè)置timer = nil就會(huì)crash。
3.在suspend(暫停)的狀態(tài)下,即使調(diào)用dispatch_source_cancel也沒用,會(huì)造成內(nèi)存泄漏,甚至崩潰。
后記:
GCDTimer的優(yōu)勢(shì):不受當(dāng)前runloopMode的影響。
劣勢(shì):其計(jì)時(shí)效應(yīng)仍不是百分之百準(zhǔn)確的。另外,他的觸發(fā)事件也有可能被阻塞,當(dāng)GCD內(nèi)部管理的所有線程都被占用時(shí),其觸發(fā)事件將被延遲