多線程下關(guān)于NSTimer不釋放的問(wèn)題
前言
前段時(shí)間由于項(xiàng)目需要,用到NSTimer渗饮,考慮到不占用主線程資源但汞,故把timer放在子線程運(yùn)行。前幾天發(fā)現(xiàn)該controller pop之后并沒(méi)有釋放互站,問(wèn)題定位到NSTimer這里私蕾。經(jīng)過(guò)測(cè)試發(fā)現(xiàn)NSTimer在多線程下不釋放的問(wèn)題,但是找不到原因胡桃。由于工作關(guān)系踩叭,未能繼續(xù)進(jìn)行問(wèn)題定位追蹤,所以先記錄下來(lái)翠胰。若有同行看到并且有答案容贝,望賜教。
正文
使用子線程創(chuàng)建NSTimer
代碼:
- (void)createThread {
self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(createTimer) object:nil];
[self.thread start];
}
- (void)createTimer
{
NSTimer *t = [NSTimer scheduledTimerWithTimeInterval:1.f target:self selector:@selector(repeat) userInfo:nil repeats:YES];
self.timer = t;
[[NSRunLoop currentRunLoop] run];
}
- (void)repeat
{
NSLog(@"repeat --- ");
}
- (void)stopTimer
{
[self.timer invalidate];
self.timer = nil;
}
解開引用循環(huán)仍無(wú)法正常釋放
如上代碼之景,這里會(huì)循環(huán)引用斤富,
self-->timer;
timer-->self锻狗;
self-->thread满力;
thread(RunLoop)-->timer焕参。
理論上,在pop controller前調(diào)用- (void)stopTimer油额,self.timer會(huì)調(diào)用-(void)invalidate方法是的Timer對(duì)self的強(qiáng)引用解除叠纷,thread(RunLoop)對(duì)timer的強(qiáng)引用解除(詳見(jiàn)invalidate的文檔描述)。但是實(shí)際測(cè)試發(fā)現(xiàn)潦嘶,調(diào)用- (void)stopTimer后雖然timer停止了涩嚣,但是pop controller后,controller并沒(méi)有釋放衬以。
在同一子線程執(zhí)行- (void)stopTimer
查閱了一些資料缓艳,有這么一個(gè)說(shuō)法:需在timer運(yùn)行的線程下執(zhí)行-(void)invalidate才有效果。抱著懷疑的態(tài)度(因?yàn)閷?shí)際上看峻,像上面的代碼一樣,在主線程調(diào)用衙吩,一樣能使timer停止)在同一線程執(zhí)行-(void)invalidate互妓,如下代碼:
[self performSelector:@selector(stopTimer) onThread:self.thread withObject:nil waitUntilDone:YES];
結(jié)果依舊是沒(méi)有釋放。
在timer的repeat中執(zhí)行- (void)stopTimer
我也不知道為什么會(huì)做這樣的嘗試坤塞,或許是程序員的直覺(jué)吧冯勉。
于是在repeat中添加如下代碼:
- (void)repeat
{
static int i = 0;
NSLog(@"repeat --- ");
i++;
if (i >=2) {
[self.timer invalidate];
}
}
這一試,我更凌亂了摹芙,controller能夠正常釋放灼狰。因?yàn)楹蜕厦鎳L試是一樣在同一線程執(zhí)行-(void)invalidate的,但這樣controller能夠正常釋放浮禾。反復(fù)思量交胚,我找不出兩者的區(qū)別在哪里,所以我很凌亂盈电。
結(jié)語(yǔ)
我并沒(méi)有解決這個(gè)問(wèn)題蝴簇,在這里只是提出了一個(gè)問(wèn)題,并且做了一些思考和嘗試匆帚,可能是自己知識(shí)還有所欠缺熬词,之后會(huì)找時(shí)間再去研究一下這個(gè)問(wèn)題。
看到這里的你或許有答案吸重,望賜教互拾。