iOS NSTimer不被释放的若干问题

 
  

demo下载地址

_timer = [NSTimer scheduledTimerWithTimeInterval:3.0f
                                              target:self
                                            selector:@selector(timerFire:)
                                            userInfo:nil
                                             repeats:YES];
    [_timer fire];
-(void)dealloc {
    [_timer invalidate];
    NSLog(@"%@ dealloc", NSStringFromClass([self class]));
}

参考博客1  参考博客2

在使用NSTimer时发现,当页面返回时计时器并没有停止

也就是说,VC的销毁方法并没有走,VC并没有被销毁,查询得知

timer是在Runloop中运行的,会被Runloop强引用

Note in particular that run loops maintain strong references to their timers, so you don’t have to maintain your own strong reference to a timer after you have added it to a run loop.

而Timer的Target的也会强引用VC,导致VC不能被释放,所以dealloc不会被调用,Timer也不会被销毁。

iOS NSTimer不被释放的若干问题_第1张图片

第一种方法,暴力的解决办法,

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [self.timer invalidate];
    self.timer = nil;
}
可以解决部分情景下的Timer和VC的释放问题,但是如果VC界面消失时并不想销毁Timer那怎么办呢,基本思路就是提供一个"假"target给timer,

第二种方法,创建一个中间类,让中间类弱引用VC,当VC执行dealloc方法时,在dealloc里销毁timer。

参考博客

第三种方法,创建timer的分类,将timer的target指向分类的静态方法,分类的实现方法如下,demo地址

+ (NSTimer *)helper_scheduedTimerWithTimeInterval:(NSTimeInterval)seconds
                                            block:(void(^)(id info))block
                                         userinfo:(id)userinfo
                                          repeats:(BOOL)repeats;
//将nstimer的target指向NSTimer类和类方法
+ (NSTimer *)helper_scheduedTimerWithTimeInterval:(NSTimeInterval)seconds
                                            block:(void (^)(id))block
                                         userinfo:(id)userinfo
                                          repeats:(BOOL)repeats
{
    return [NSTimer scheduledTimerWithTimeInterval:seconds
                                            target:self
                                          selector:@selector(helper_block:)
                                          userInfo:@[[block copy] , userinfo]
                                           repeats:repeats];
}
//在类方法中回调block
+ (void)helper_block:(NSTimer *)timer
{
    NSArray *infoArr = timer.userInfo;
    void (^myblock)(id userinfo) = infoArr[0];
    id info = infoArr[1];
    
    if (myblock) {
        myblock(info);
    }
}

使用时的代码如下

@weakify(self);
    self.timer = [NSTimer helper_scheduedTimerWithTimeInterval:1.0 block:^(id info) {
        @strongify(self);
        [self print:info];
    } userinfo:@[@"1" , @"2"] repeats:YES];
- (void)print:(id)info
{
    NSLog(@"执行block:%@" , info);
}
- (void)dealloc
{
    [self.timer invalidate];
    self.timer = nil;
    NSLog(@"销毁了B");
}

第四种办法,使用苹果最新的方法

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

这个方法跟第三种方法比较类似,苹果在这个方法中解决了内存泄露的问题,但是这个方法的版本比较高,使用不方便。


标注:weakly和strongify是yykit里的一个宏定义,

/**
 Synthsize a weak or strong reference.
 
 Example:
    @weakify(self)
    [self doSomething^{
        @strongify(self)
        if (!self) return;
        ...
    }];

 */
#ifndef weakify
    #if DEBUG
        #if __has_feature(objc_arc)
        #define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
        #else
        #define weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
        #endif
    #else
        #if __has_feature(objc_arc)
        #define weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
        #else
        #define weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
        #endif
    #endif
#endif

#ifndef strongify
    #if DEBUG
        #if __has_feature(objc_arc)
        #define strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
        #else
        #define strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
        #endif
    #else
        #if __has_feature(objc_arc)
        #define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
        #else
        #define strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
        #endif
    #endif
#endif



你可能感兴趣的:(OC)