iOS开发中利用block解决NSTimer的循环引用问题
这篇文章已经给出了解决使用NSTimer造成的循环引用的方法,本篇文章再给出另一种解决方法。
NSTimer造成循环引用的原因
NSTimer对象和其target(ViewController)互为强引用,造成循环引用,从而导致NSTimer对象持有的控制器无法释放。
NSTimer实例对target进行的是强引用,即使我们对它的target进行了弱化即使用了weak,可由于传递的是一个地址,仍然无效(weak是用来解决block造成的循环引用的)。之前的解决方法是将target指向了NSTimer实例自己,我们还可以使用一个中间代理来解决NSTimer造成的循环引用。
解决循环引用
我们无法修改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