排除NSTimer对目标对象的保留
来源:互联网 发布:程序员自我评价幽默 编辑:程序博客网 时间:2024/04/28 17:50
NSTimer是我们常用的对象。但如果使用不当就有可能出现循环引用,造成内测泄漏。
计时器要和运行循环相关联,运行循环到时候会触发任务的执行。
NSTimer的创建可以预先安排在当前的运行循环中,也可以先创建好,然后由开发者自己来调用。不管使用哪种方式,都只有将NSTimer对象放到运行循环中才能使其正常工作。
例如以如下方法,我们创建一个NSTimer.
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerFired:) userInfo:nil repeats:YES];
如果我们这样使用NSTimer,就很有可能造成循环引用所导致的内测泄漏。
1.原因分析:
timer是一个由当前self对象强引用的属性。timer对象的target参数是self,这时timer就对self对象产生了强引用。
这个方法对target参数是这样解释的
target:The object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to target until it (the timer) is invalidated.
所以如果我们想要释放掉timer可以调用invalidated方法。但是如果放到dealloc中,该timer依然释放不掉,因为这个dealloc方法根本不会执行。这是由于timer对self强引用,导致self无法释放,自然dealloc方法就没法调用。
2.解决办法
1)狭隘的做法
如果当前的self是一个控制器的话,那么我们有可能会在
dealloc方法中调用timer的invalidated方法。但是这样依然无法导致timer的失效,从而导致定时器和控制器都不能释放。所以靠谱一点的做法是放在viewWillDisappear中
- (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if ([self.timer isValid]) { [self.timer invalidate]; }}
这样真的可以解决问题。但是这样真的好吗?有通用性吗,如果当前的self不是控制器对象呢,那你的invalidate方法放在什么地方进行调用呢。
2)方案二:给NSTimer增加一个分类
核心代码:
@interface NSTimer (YCClass)+ (NSTimer *)yc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats;@end@implementation NSTimer (YCClass)+ (NSTimer *)yc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats{return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(yc_blockInvoke:) userInfo:[block copy] repeats:repeats];}+ (void)yc_blockInvoke:(NSTimer *)timer {void (^block)() = timer.userinfo;if(block) { block();}}@end
分析:现在的target对象是NSTimer类对象,是一个单例。此处依然有自我形成的环,但是类对象无需回收,所以不用担心内存泄露的问题。
3)方案三:新增一个类对self进行弱引用
这是从YYKit中看到的解决方案,觉得很不错,现引用如下:
#import "YYWeakProxy.h"@implementation YYWeakProxy- (instancetype)initWithTarget:(id)target { _target = target; return self;}+ (instancetype)proxyWithTarget:(id)target { return [[YYWeakProxy alloc] initWithTarget:target];}- (id)forwardingTargetForSelector:(SEL)selector { return _target;}- (void)forwardInvocation:(NSInvocation *)invocation { void *null = NULL; [invocation setReturnValue:&null];}- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { return [NSObject instanceMethodSignatureForSelector:@selector(init)];}- (BOOL)respondsToSelector:(SEL)aSelector { return [_target respondsToSelector:aSelector];}- (BOOL)isEqual:(id)object { return [_target isEqual:object];}- (NSUInteger)hash { return [_target hash];}- (Class)superclass { return [_target superclass];}- (Class)class { return [_target class];}- (BOOL)isKindOfClass:(Class)aClass { return [_target isKindOfClass:aClass];}- (BOOL)isMemberOfClass:(Class)aClass { return [_target isMemberOfClass:aClass];}- (BOOL)conformsToProtocol:(Protocol *)aProtocol { return [_target conformsToProtocol:aProtocol];}- (BOOL)isProxy { return YES;}- (NSString *)description { return [_target description];}- (NSString *)debugDescription { return [_target debugDescription];}
他的.h文件是这样的
@interface YYWeakProxy : NSProxy@property (nullable, nonatomic, weak, readonly) id target;- (instancetype)initWithTarget:(id)target;+ (instancetype)proxyWithTarget:(id)target;@end
所以我们在使用定时器的时候就很简单
YYWeakProxy *weakProxy = [YYWeakProxy proxyWithTarget:self]; self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:weakProxy selector:@selector(timerFired:) userInfo:nil repeats:YES];
分析:该方法主要让timer强引用YYWeakProxy对象,但是该对象却对self对象弱引用,并将timerFired方法转发给self对象。这样当外界不对self强引用的时候,self就会被销毁掉,这样self所强引用的timer对象因为没有外界的强引用也会被销毁。
- 排除NSTimer对目标对象的保留
- NSTimer会保留其目标对象
- 写高质量OC代码52建议总结:52.NSTimer会保留其目标对象
- NSTIMER 的保留环问题解决方法
- ARC下用Block解决NSTimer"保留环"的问题
- NSTimer详解----使用、保留环问题、与runloop的关系
- 继承方式实现对目标对象的方法增强
- 学习笔记:结构保留的目标跟踪
- NSTimer 对解码与显示的影响
- 对NSTimer问题的小总结
- ios NSTimer与保留环
- 面向对象的目标
- gson排除字段,包含字段工具类大全,构建普通的gson对象,包括对时间的转换
- 对伪目标的理解
- 避免滑动tableView时对NSTimer的干…
- 弱引用NSTimer对象
- IO目标对象的细节
- 对用用户密码的保留方式
- 第四章 上机4
- HTML笔记(二)
- sip服务器判断同一个transaction条件
- python 里面的单下划线与双下划线的区别(私有和保护)
- 安卓资源库
- 排除NSTimer对目标对象的保留
- iTextSharp5.0页眉页脚及Asp.net预览的实现(PDF导出)
- 输入错误,catch 无限循环
- 小程序WXML之条件渲染
- Python串口发送HEX数组
- github学习--本地仓库同步github远程仓库出现的问题
- SpringMVC给控制器添加自定义注解控制访问权限
- Part 7 - Setting an item selected when an asp.net mvc dropdownlist is loaded
- 参数个数可变函数