iOS开发中的内存管理之解决NSTimer造成的循环引用

iOS开发中利用block解决NSTimer的循环引用问题
这篇文章已经给出了解决使用NSTimer造成的循环引用的方法,本篇文章再给出另一种解决方法。

NSTimer造成循环引用的原因

0.Timer循环引用.png

NSTimer对象和其target(ViewController)互为强引用,造成循环引用,从而导致NSTimer对象持有的控制器无法释放。
NSTimer实例对target进行的是强引用,即使我们对它的target进行了弱化即使用了weak,可由于传递的是一个地址,仍然无效(weak是用来解决block造成的循环引用的)。之前的解决方法是将target指向了NSTimer实例自己,我们还可以使用一个中间代理来解决NSTimer造成的循环引用。

解决循环引用

0.中间代理.png

我们无法修改NSTimer内部代码,我们可以使用一个中间代理作为NSTimer的target,然后将这个中间代理的target指向当前VC,且对当前VC的引用是一个弱引用。
这里我们使用的中间代理名叫LSObjectProxy,看代码:

  self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[LSObjectProxy proxyWithTarget:self] selector:@selector(timerAction) userInfo:nil repeats:YES];

LSObjectProxy内部代码:

@interface LSObjectProxy : NSObject

+ (instancetype)proxyWithTarget:(id)target;
@property (nonatomic, weak) id target;

@end    

+ (instancetype)proxyWithTarget:(id)target{
LSObjectProxy * proxy = [[LSObjectProxy alloc] init];
proxy.target = target;
return proxy;
}

// 转发目标选择器
- (id)forwardingTargetForSelector:(SEL)aSelector{

return self.target;
}

注意:这种消息转发方式属于快速转发
NSTimer定时执行的事件交给了中间代理LSObjectProxy去处理,可现在该事件是在当前VC中去处理的,这时我们需要用到消息转发,在代理内部将处理的定时事件转发给当前VC,所以用到了方法forwardingTargetForSelector,指定了处理事件的对象。
我们还可以优化一下这个中间代理,下篇文章再介绍。

demo地址:https://github.com/yangguanghei/-NSTimer-.git

问题:将NSTimer属性设置为weak类型不行吗?
答:NSTimer被添加到了RunLoop中,RunLoop对NSTimer对象也是强引用,只有当NSTimer对象调用invalidate方法的时候RunLoop才会释放对NSTimer对象的强引用,所以设置weak无效。

个人比较喜欢NSTimer的带有block的创建方法不用管这么多,如果是需要一个定时器更喜欢GCD的创建方式,大家可以看下https://www.jianshu.com/p/e6823e1a9e8e

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容