iOS中定時器的使用
demo地址:
https://github.com/liuxuleidota/LXLGCDTimer
使用NSTimer蔚万,注意點:
一、切換runloop時失效
默認情況下NSTimer會加入到runloop defaultMode中早敬,當界面上有scrollview滑動時,runloop會切換到trackingMode每强,此時NSTimer會暫停稿静,如果要避免此情況,如下:
- (IBAction)startNSTimer:(id)sender {
_nsTimer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"%@ xxxx", NSTimerName);
}];
[[NSRunLoop mainRunLoop] addTimer:_nsTimer forMode:NSRunLoopCommonModes];
}
二桶雀、可能引起內(nèi)存泄漏
NSTimer與self相互持有矿酵,使用weakSelf解除循環(huán)引用:
__weak typeof(self) weakSelf = self;
NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
[weakSelf doSth];
}];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
這樣self可以正常走dealloc,但是矗积,在self銷毀后全肮,timer并不會銷毀!因為runloop仍然持有著timer
所以需要在必要的位置棘捣,停止timer辜腺,比如viewController的viewWillDisapper中(但是viewWillDisapper調(diào)用時機有很多,只要有新的controller覆蓋當前的controller,此方法就會調(diào)用评疗,所以是否要在viewWillDisapper中調(diào)用测砂,請根據(jù)自己的業(yè)務邏輯來處理)
我的做法:
//runloop雖然會強持有timer,但是是在把timer加入runloop之后百匆,所以還是要強持有timer砌些,arc會處理這個strong,沒關系
@property(nonatomic, strong) NSTimer *nsTimer;
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[self cancelNSTimer];
}
- (void)dealloc{
[self cancelNSTimer];
NSLog(@"%@ is dealloced, timer=%@", self, _nsTimer);
}
- (void)doSth{
//doSth
//when sth is done
[self cancelNSTimer];
}
- (void)cancelNSTimer{
if (!_nsTimer) {
return;
}
//從runloop移除timer
[_nsTimer invalidate];
//將timer置為nil加匈,如果沒有此行存璃,在dealloc中打印仍然可以看到timer不為空
//至于在dealloc方法走完,self銷毀后雕拼,timer是否被銷毀纵东,這里沒有進一步測試,因為NSTimer不能子類化
_nsTimer = nil;
}
三啥寇、不能跨線程操作NSTimer?
此點有疑問篮迎,如下:
- (void)cancelNSTimer{
if (!_nsTimer) {
return;
}
dispatch_queue_t queue = dispatch_queue_create("com.levi.queue", NULL);
dispatch_sync(queue, ^{
[_nsTimer invalidate];
_nsTimer = nil;
});
}
timer是在主線程中創(chuàng)建的,但是這里我在子線程中操作示姿,同樣有效甜橱,有知道的請解答下
使用GCDTimer
引入demo中LXLGCDTimer目錄
一、創(chuàng)建GCDTimer
- (IBAction)startGCDTimer:(id)sender {
[LXLGCDTimerManager.sharedInstance scheduleGCDTimerWithName:self.timerName interval:1 queue:dispatch_get_main_queue() repeats:YES option:CancelPreviousTimerAction action:^{
//此方法中請使用weakSelf
NSLog(@"%@ xxxx", GCDTimerName);
}];
}
二栈戳、實現(xiàn)以下方法
//也可自己實現(xiàn)timerName方法岂傲,達到同一界面添加多個定時器目的
- (NSString *)timerName{
return [NSString stringWithFormat:@"%@timer", NSStringFromClass(self.class)];
}
- (void)cancelGCDTimer{
[LXLGCDTimerManager.sharedInstance cancelTimerWithName:self.timerName];
}
//適當位置取消定時器,不然也會出現(xiàn)像NSTimer一樣的情況子檀,controller已經(jīng)銷毀镊掖,但是定時器仍然在運行!
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[self cancelGCDTimer];
}
- (void)dealloc{
[self cancelGCDTimer];
}
本來想寫的標題是用gcdTimer替代NSTimer可以避免很多坑褂痰,但是寫完發(fā)現(xiàn)其實NSTimer使用正確的話亩进,代碼量跟gcdTimer是一樣的(還不包括引入的LXLGCDTimer!)
總結:都可以用缩歪!