1.NSTimer
創(chuàng)建NSTimer
//常用方法
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
//常用方法
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep
- scheduledTimerWithTimeInterval 方法相比timerWithTimeInterval,不僅初始化了一個(gè)timer對象,同時(shí)還將該對象放入到當(dāng)前的Runloop中,而后者需要手動(dòng)將timer放入runloop。最重要的是NSTimer只有放到runloop才會生效。(runloop后面會專門寫一下)。
-(void)addTimer:(NSTimer *)aTimer forMode:(NSString *)mode
- timer定時(shí)器并不是一個(gè)精確運(yùn)行的,精確運(yùn)行需要用GCDtimer
- 正常情況下tableView等滾動(dòng)視圖添加timer后,視圖滾動(dòng)后
RunLoop會將mode切換成TrackingRunLoopMode 不會調(diào)用timer
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateUI) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
//NSRunLoopCommonModes的意思為,定時(shí)器可以運(yùn)行在標(biāo)記為common modes模式下。
//具體包括兩種: kCFRunloopDefaultMode 和 UITrackingRunloopMode。
[timer fire];
暫停/啟動(dòng)NSTimer
//啟動(dòng),常用方法創(chuàng)建的直接就啟動(dòng)了
[self.timer setFireDate:[NSDate distantPast]];
//暫停
[self.timer setFireDate:[NSDate distantFuture]];
釋放NSTimer
釋放寫在viewWillDisappear!!!!!
[self.timer invalidate];//將timer停止并移出runloop
self.timer = nil;
NSTimer在ARC下
初始化后放到runloop后,除了ViewController外,iOS系統(tǒng)也強(qiáng)引用NSTimer對象。
將timer對象置nil后,會解除VC對timer的中引用。但iOS系統(tǒng)依然對NSTimer和VC存在強(qiáng)引用關(guān)系。(因?yàn)椴⑽唇獬到y(tǒng)對timer的強(qiáng)引用,并且系統(tǒng)為了實(shí)現(xiàn)NSTimer而對VC繼續(xù)保持引用)。所以先對timer 執(zhí)行invalidate(解系統(tǒng)對timer的強(qiáng)引用),再置nil(解除VC對timer引用)。
由于系統(tǒng)和VC對timer的雙重引用,導(dǎo)致dealloc 方法無法執(zhí)行,所以理想的方法是釋放代碼寫在viewWillDisappear方法中。
2.GCD
dispatch source是一個(gè)監(jiān)視某些類型事件的對象。
當(dāng)這些事件發(fā)生時(shí),它自動(dòng)將一個(gè)block放入一個(gè)dispatch queue的執(zhí)行例程中。
/**
* 創(chuàng)建dispatch源
*
* @param DISPATCH_SOURCE_TYPE_TIMER 事件源的類型
* @param 0 <#0 description#>
* @param 0 <#0 description#>
* @param dispatch_get_main_queue 在哪個(gè)線程上執(zhí)行
*
* @return dispatch_source_t
*/
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
/**
* @param start 控制計(jì)時(shí)器第一次觸發(fā)的時(shí)刻
* @param interval 每隔多長時(shí)間執(zhí)行一次
* @param leeway 誤差值,0表示最小誤差,值越小性能消耗越大
*/
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
//事件處理的回調(diào)
dispatch_source_set_event_handler(timer, ^{
});
// Dispatch source啟動(dòng)時(shí)默認(rèn)狀態(tài)是掛起的,創(chuàng)建完畢之后得主動(dòng)恢復(fù),
//否則事件不會被傳遞,也不會被執(zhí)行
dispatch_resume(timer);
//取消定時(shí)器
dispatch_cancel(timer);
3.CADisplayLink
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(disPlay)];
//與NSTimer不同, 需要手動(dòng)添加到RunLoop中, 如果添加的模式是NSDefaultRunLoopMode, 則scrollview滾動(dòng)時(shí), 會阻礙定時(shí)器的執(zhí)行。
//如果是NSRunLoopCommonModes, 則不會阻礙。
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
//設(shè)置刷新頻率, 默認(rèn)是每秒60幀, 如果設(shè)置成60就每秒執(zhí)行一次
//但是實(shí)際測試卻發(fā)現(xiàn),設(shè)置60是2秒執(zhí)行一次, 設(shè)置成30才是每秒執(zhí)行一次。但精度依然比NSTimer高
displayLink.frameInterval = 60;