NSTimer内存泄露解决方法

2019-12-02  本文已影响0人  浪淘沙008
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(test) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

由于NSTimer会持有我们设置的target对象,而RunLoop也会对timer对象持有,主线程的RunLoop是一直存在的,即便设置为weak属性timer也不会被释放,所以在上面的方式添加定时器时会造成内存的泄露,解决上面的问题可以通过将timer设置为属性在对象即将消失的方法中对timer对象进行释放从而解决循环引用,代码如下:

@property (nonatomic, strong) NSTimer * timer;

self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(test) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
    
- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [self.timer invalidate];
    self.timer = nil;
}

在上面的方法中需要我们手动调用timer的释放工作从而解决存在的循环引用问题,对待此类问题的另一种解决方案是通过一个中间对象A持有timer,在A中判断target对象是否还存在并决定timer是否需要释放,从而解决每次都需要手动释放timer的问题,代码如下:

// category的.h
#import <Foundation/Foundation.h>

@interface NSTimer (WeakTimer)
+ (NSTimer *)scheduledWeakTimerWithTimeInterval:(NSTimeInterval)interval
  target:(id)aTarget
selector:(SEL)aSelector
userInfo:(id)userInfo
 repeats:(BOOL)repeats;
@end

// category的.m
#import "NSTimer+WeakTimer.h"

@interface TimerWeakObject : NSObject
@property (nonatomic, weak) id target;
@property (nonatomic, assign) SEL selector;
@property (nonatomic, weak) NSTimer *timer;

- (void)fire:(NSTimer *)timer;
@end

@implementation TimerWeakObject

- (void)fire:(NSTimer *)timer
{
    if (self.target) {
        if ([self.target respondsToSelector:self.selector]) {
            [self.target performSelector:self.selector withObject:timer.userInfo];
        }
    }
    else{
        [self.timer invalidate];
        self.timer = nil;
    }
}

@end

@implementation NSTimer (WeakTimer)
+ (NSTimer *)scheduledWeakTimerWithTimeInterval:(NSTimeInterval)interval
                                         target:(id)aTarget
                                       selector:(SEL)aSelector
                                       userInfo:(id)userInfo
                                        repeats:(BOOL)repeats
{
    TimerWeakObject *object = [[TimerWeakObject alloc] init];
    object.target = aTarget;
    object.selector = aSelector;
    object.timer = [NSTimer scheduledTimerWithTimeInterval:interval target:object selector:@selector(fire:) userInfo:userInfo repeats:repeats];
    return object.timer;
}
@end

//调用,无需手动释放所以不需要声明成员变量
[[NSRunLoop currentRunLoop] addTimer:[NSTimer scheduledWeakTimerWithTimeInterval:1.0 target:self selector:@selector(test) userInfo:nil repeats:YES] forMode:NSDefaultRunLoopMode];

上一篇 下一篇

猜你喜欢

热点阅读