iOS-解决NSTimer引起的内存泄漏问题
pop timer所在的控制器,会发现timer还在运行,因为tiemr创建加入了runloop中,如果不主动的调用 invalidate 方法,timer是不会被释放掉的,根本停不下来。
重写dealloc方法,发现pop不走dealloc方法,所以在dealloc中调用invalidate也是没有用的。
控制器要释放掉,则需释放掉所有的实例变量,释放timer,但是释放掉timer则必须释放掉它持有target,由于初始化时timer的target设置为了self,就是当前控制器,所以造成了循环引用,内存泄漏了。
解决办法就是:解除timer对self的强引用,把target替换成单独的对象,再利用消息转发/消息传递使得单独对象中的timer的SEL方法在控制器中实现
方法一:使用NSProxy解决NSTimer内存泄漏问题,利用消息转发来断开NSTimer对象与视图之间的引用关系
@interface TimerProxy : NSProxy- (instancetype)initWithTarget:(id)target;
@end
#import "TimerProxy.h"@interface TimerProxy ()@property (nonatomic,weak)id target;
@end@implementation TimerProxy- (instancetype)initWithTarget:(id)target {self.target = target;
return self;
}/*
这个函数让重载方有机会抛出一个函数的签名,再由后面的forwardInvocation:去执行
*/
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.target methodSignatureForSelector:sel];
}/*
将消息转发给其他对象,这里转发给控制器
*/
- (void)forwardInvocation:(NSInvocation *)invocation {
SEL sel=[invocation selector];
if ([self.target respondsToSelector:sel]) {
[invocation invokeWithTarget:self.target];
}
}
【iOS-解决NSTimer引起的内存泄漏问题】使用方法:
- (void)proxy {TimerProxy *proxy=[[TimerProxy alloc]initWithTarget:self];
timer =[NSTimer timerWithTimeInterval:1 target:proxy selector:@selector(timeAction) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
}
- (void)timeAction {
time++;
self.timeLabel.text=[NSString stringWithFormat:@"%d",time];
NSLog(@"time%d",time);
}
- (void)dealloc {
[timer invalidate];
}
方法二:使用 消息传递 解决NSTimer内存泄漏问题
创建一个对象,让NSTimer对这个对象进行强引用,而不对控制器进行强引用
@interface WeakTimeObject : NSObject+ (NSTimer *)weakScheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval target:(id)target selector:(SEL)sel userInfo:(id)userInfo repeats:(BOOL)isRepeats;
@end
@interface WeakTimeObject ()@property (nonatomic,weak) id target;
@property (nonatomic,assign)SEL selector;
@end@implementation WeakTimeObject+ (NSTimer *)weakScheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval target:(id)target selector:(SEL)sel userInfo:(id)userInfo repeats:(BOOL)isRepeats {WeakTimeObject *objc=[[WeakTimeObject alloc]init];
objc.target = target;
objc.selector = sel;
//Nstimer 对 WeakTimeObject 对象 强引用
return [NSTimer scheduledTimerWithTimeInterval:timeInterval target:objc selector:@selector(timeAction:) userInfo:userInfo repeats:isRepeats];
}//消息传递,在 self.target运行 self.selector 方法
- (void)timeAction:(id)info {
[self.target performSelector:self.selector withObject:info];
}
使用方法
- (void)objc {
timer = [WeakTimeObject weakScheduledTimerWithTimeInterval:1.0 target:self selector:@selector(update) userInfo:nil repeats:YES];
}
- (void)update {
time++;
self.timeLabel.text=[NSString stringWithFormat:@"%d",time];
NSLog(@"time%d",time);
}- (void)dealloc {
[timer invalidate];
}
推荐阅读
- parallels|parallels desktop 解决网络初始化失败问题
- 考研英语阅读终极解决方案——阅读理解如何巧拿高分
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- Spark|Spark 数据倾斜及其解决方案
- 解决SyntaxError:|解决SyntaxError: invalid syntax
- Spectrum|Spectrum 区块偶尔停止同步问题排查与解决笔记
- 一劳永逸地解决词汇量不够的问题
- Hexo代码块前后空白行问题