在一次實踐中,創(chuàng)建了控制器,控制器中創(chuàng)建了timer和手勢,控制器的view被addsubview到window上,手動或者3s后從window上移除。
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor=RGBA_COLOR(0, 0, 0, 0.4);
_timer=[NSTimer timerWithTimeInterval:3.0
target:self
selector:@selector(action)
userInfo:nil
repeats:NO];
UITapGestureRecognizer* tap= [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(action)];
[self.view addGestureRecognizer:tap];
}
并將timer加入到了當(dāng)前的runloop中
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self startTimer];//開始計時
}
- (void)startTimer {
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
}
-(void)action
{
[_timer invalidate];
_timer = nil;
if (![self popNext]) {
[self.view removeFromSuperview];
}else {
_timer=[NSTimer timerWithTimeInterval:3.0
target:self
selector:@selector(action)
userInfo:nil
repeats:NO];
[self startTimer];
}
}
運(yùn)行在iOS9以下的系統(tǒng)手勢觸發(fā)會發(fā)上crash。
屏幕快照 2016-12-19 22.03.48.png
原因是該控制器創(chuàng)建后只有timer持有了該控制器。( timer對target對象強(qiáng)引用,當(dāng)timer中repeat設(shè)置為NO時,timer到時間觸發(fā)執(zhí)行action后即對target不再引用;當(dāng)timer中repeat設(shè)置為YES時,timer會持續(xù)持有target,直到手動invalidate timer后會釋放。)當(dāng)timer被invalidate后對象就釋放了,再次訪問timer就會報錯。
可是ios9及以上的系統(tǒng)就不會,由于ios9以上系統(tǒng)對內(nèi)存回收機(jī)制做了修改,當(dāng)對象函數(shù)運(yùn)行中對對象本身進(jìn)行釋放時,會到函數(shù)運(yùn)行結(jié)束完后才真正釋放,ios9以前的系統(tǒng)會在函數(shù)運(yùn)行中立即釋放對象,不會等到函數(shù)運(yùn)行結(jié)束,如果該函數(shù)之后對對象進(jìn)行操作就會crash。