iOS NSTimer导致内存泄露问题
2020-03-17 本文已影响0人
HCL黄
通常情况下
- 初始化
NSTimer
- (void)viewDidLoad {
[super viewDidLoad];
self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}
- 执行timer方法
- (void)timerAction {
NSLog(@"timerAction");
TimerInteger += 1;
self.label.text = @(TimerInteger).stringValue;
}
- 最后销毁控制器的时候停止定时器并置空
- (void)dealloc {
NSLog(@"dealloc");
[self.timer invalidate];
self.timer = nil;
}
然而当我们退出控制器的时候,并不会调用dealloc
,导致定时器一直存在,这样就有可能导致内存得不到释放,从而导致内存泄露
通过中间变量来解决这一问题
- 新建一个
LATimerTarget
对象
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface LATimerTarget : NSObject
@property (nonatomic, copy) void(^targetBlock)(void);
- (void)timerTargetAction;
@end
NS_ASSUME_NONNULL_END
#import "LATimerTarget.h"
@implementation LATimerTarget
- (void)timerTargetAction {
NSLog(@"timerTargetAction");
if (self.targetBlock) {
self.targetBlock();
}
}
@end
- 让
NSTimer
的target设置为LATimerTarget
对象,selector选择器调用LATimerTarget
的方法- (void)timerTargetAction;
,控制器需要处理的逻辑在LATimerTarget
的targetBlock
进行处理
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.label = [[UILabel alloc] init];
self.label.backgroundColor = [UIColor greenColor];
self.label.font = [UIFont systemFontOfSize:20];
self.label.frame = CGRectMake(0, 100, 200, 100);
[self.view addSubview:self.label];
/**
当target为self的时候,退出该控制器时,dealloc是不会调用的,这会导致内存泄露
*/
// self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
// [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
/**
target设置为LATimerTarget对象,并且在LATimerTarget新增timerTargetAction方法
通过targetBlock回调,进行UI逻辑处理
这个时候我们退出该控制器时,dealloc调用,移除定时器
*/
LATimerTarget *target = [[LATimerTarget alloc] init];
__weak __typeof(&*self)weakSelf = self;
target.targetBlock = ^{
TimerInteger += 1;
weakSelf.label.text = @(TimerInteger).stringValue;
};
self.timer = [NSTimer timerWithTimeInterval:1 target:target selector:@selector(timerTargetAction) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}