多线程下关于NSTimer不释放的问题
前言
前段时间由于项目需要,用到NSTimer,考虑到不占用主线程资源,故把timer放在子线程运行。前几天发现该controller pop之后并没有释放,问题定位到NSTimer这里。经过测试发现NSTimer在多线程下不释放的问题,但是找不到原因。由于工作关系,未能继续进行问题定位追踪,所以先记录下来。若有同行看到并且有答案,望赐教。
正文
使用子线程创建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;
}
解开引用循环仍无法正常释放
如上代码,这里会循环引用,
self-->timer;
timer-->self;
self-->thread;
thread(RunLoop)-->timer。
理论上,在pop controller前调用- (void)stopTimer,self.timer会调用-(void)invalidate方法是的Timer对self的强引用解除,thread(RunLoop)对timer的强引用解除(详见invalidate的文档描述)。但是实际测试发现,调用- (void)stopTimer后虽然timer停止了,但是pop controller后,controller并没有释放。
在同一子线程执行- (void)stopTimer
查阅了一些资料,有这么一个说法:需在timer运行的线程下执行-(void)invalidate才有效果。抱着怀疑的态度(因为实际上,像上面的代码一样,在主线程调用,一样能使timer停止)在同一线程执行-(void)invalidate,如下代码:
[self performSelector:@selector(stopTimer) onThread:self.thread withObject:nil waitUntilDone:YES];
结果依旧是没有释放。
在timer的repeat中执行- (void)stopTimer
我也不知道为什么会做这样的尝试,或许是程序员的直觉吧。
于是在repeat中添加如下代码:
- (void)repeat
{
static int i = 0;
NSLog(@"repeat --- ");
i++;
if (i >=2) {
[self.timer invalidate];
}
}
这一试,我更凌乱了,controller能够正常释放。因为和上面尝试是一样在同一线程执行-(void)invalidate的,但这样controller能够正常释放。反复思量,我找不出两者的区别在哪里,所以我很凌乱。
结语
我并没有解决这个问题,在这里只是提出了一个问题,并且做了一些思考和尝试,可能是自己知识还有所欠缺,之后会找时间再去研究一下这个问题。
看到这里的你或许有答案,望赐教。
网友评论