OC底层相关

如何解决NSTimer循环引用问题

2019-04-27  本文已影响4人  繁星mind

1.为什么会循环引用

self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(startTimer) userInfo:nil repeats:YES];

self会强引用nstimer,nstimer也会强引用target,也就是self,所以就造成了循环引用,通常的解决办法是转移target,将target转移到第三者身上,就不会造成循环引用。

2.weak指针为什么无效
既然是强引用导致循环引用,那么用__weak修饰self就好了,想法是对的,但是做法是无效的。因为无论是weak还是strong修饰,在NSTimer中都会重新生成一个新的强引用指针指向self,导致循环引用的。

3.怎么解决
解决这个问题的方法通常有两种:一种是将target分离出来独立成一个对象(在这个对象中创建NSTimer并将对象本身作为NSTimer的target),控制器通过这个对象间接使用NSTimer;另一种方式的思路仍然是转移target,只是可以直接增加NSTimer扩展(分类),让NSTimer自身做为target,同时可以将操作selector封装到block中。后者相对优雅,也是目前使用较多的方案(目前有大量类似的封装,例如:NSTimer+Block)。显然Apple也认识到了这个问题,如果你可以确保代码只在iOS 10下运行就可以使用iOS 10新增的系统级block方案(上面的代码中已经贴出这种方法)。
当然使用上面第二种方法可以解决控制器无法释放的问题,但是会发现即使控制器被释放了两个定时器仍然正常运行,要解决这个问题就需要调用NSTimer的invalidate方法(注意:无论是重复执行的定时器还是一次性的定时器只要调用invalidate方法则会变得无效,只是一次性的定时器执行完操作后会自动调用invalidate方法)。

参考:
从RunLoop源码探索NSTimer的实现原理
NSTimer循环引用解决方案
iOS刨根问底-深入理解RunLoop

上一篇 下一篇

猜你喜欢

热点阅读