全局NSTimer导致的内存泄露及解决办法

NSTimer在iOS10之前只有如下两个常用方法 

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;

这两个方法都有一个target参数,一般我们都把NSTimer对象作为一个属性,这个时候target通常传递的是NSTimer属性所在的类对象,也就是Self,由于NSTimer会强引用这个target对象,所以导致出现一些问题。

销毁NSTimer计时器只能通过- (void)invalidate方法,一般的需求下,我们期望计时器在视图的声明周期结束后停止计时器,所以我们可能想在视图类的- (void)dealloc方法中调用[self.time invalidate]来停止计时器。但是很遗憾,在视图消失的时候程序并不会调用- (void)dealloc方法,所以计时器也一直在运行,造成了内存泄露。

例如:利用以下demo进行测试

#import <UIKit/UIKit.h>

@interface TestView : UIView

@end


#import "TestView.h"

@interface TestView ()
@property (strong, nonatomic) NSTimer *timer;

@end

@implementation TestView

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        self.timer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(timerTick) userInfo:nil repeats:YES];
        [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
    }
    return self;
}
- (void)timerTick {
    NSLog(@"*******");
}
- (void)dealloc {
    if (self.timer) {
        [self.timer invalidate];
        self.timer = nil;
    }
}
- (void)willMoveToSuperview:(UIView *)newSuperview {
    [super willMoveToSuperview:newSuperview];
    if (!newSuperview && self.timer) {
        [self.timer invalidate];
        self.timer = nil;
    }
}
@end

我们知道iOS的内存管理是采用引用计数算法来实现的,当一个对象的引用计数为0的时候系统会回收该对象,对象的- (void)dealloc方法要在对象的引用计数值归零之后才会被调用,由于NSTimer计时器一直强引用着视图类对象,所以视图类对象的引用关系里面一直有计时器对象,导致引用计数不能归零,所以- (void)dealloc不会被调用。

至于解决办法,那就是在不需要计时器的时候调用- (void)invalidate方法,但是如果我们计时器的开关是交由外部程序员去实现的,那么我们就只能在文档中嘱咐对方在不需要的时候一定要记得停止计时器,这并不保险。

但是例子中的定时器封装在一个类的类部要在viewcontroller销毁的时候怎么销毁定时器呢?

可以使用例子中的- (void)willMoveToSuperView:(UIView *)newSuperview方法,可以在方法中销毁定时器,我们发现内存泄漏已经解决,dealloc方法可以执行了,此处dealloc方法可不写。

转载于:https://my.oschina.net/zsyzone/blog/1602344

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值