美文网首页iOS ProcessIOS进阶ios进阶
警惕使用NSTimer时的循环引用

警惕使用NSTimer时的循环引用

作者: 黄龙辉 | 来源:发表于2015-10-13 23:05 被阅读4071次

使用NSTimer可能会碰到循环引用的问题。特别是当类具有NSTimer类型的成员变量,并且需要反复执行计时任务时。例如

_timer = [NSTimer scheduledTimerWithTimeInterval:5.0
                                          target:self
                                        selector:@selector(startCounting) userInfo:nil
                                         repeats:YES];

类有一个成员变量_timer,给_timer设置的target为这个类本身。这样类保留_timer_timer又保留了这个类,就会出现循环引用的问题,最后导致类无法正确释放。

解决这个问题的方式也很简单,当类的使用者能够确定不需要使用这个计时器时,就调用

[_timer invalidate];
_timer = nil;

这样就打破了保留环,类也可以正确释放。但是,这种依赖于开发者手动调用方法,才能让内存正确释放的方式不是一个非常好的处理方式。所以需要另外一种解决方案。如下所示:

@interface NSTimer (JQUsingBlock)
+ (NSTimer *)jq_scheduledTimerWithTimeInterval:(NSTimeInterval)ti
                                     block:(void(^)())block
                                   repeats:(BOOL)repeats;
@end

@implementation NSTimer (JQUsingBlock)

+ (NSTimer *)jq_scheduledTimerWithTimeInterval:(NSTimeInterval)ti
                                     block:(void(^)())block
                                   repeats:(BOOL)repeats{

    return [self scheduledTimerWithTimeInterval:ti
                                     target:self
                                   selector:@selector(jq_blockInvoke:)
                                   userInfo:[block copy]
                                    repeats:repeats];
}

+ (void)jq_blockInvoke:(NSTimer *)timer{

    void(^block)() = timer.userInfo;
    if (block) {
        block();
    }
}

@end

定义一个NSTimer的类别,在类别中定义一个类方法。类方法有一个类型为块的参数(定义的块位于栈上,为了防止块被释放,需要调用copy方法,将块移到堆上)。使用这个类别的方式如下:

__weak ViewController *weakSelf = self;
_timer = [NSTimer jq_scheduledTimerWithTimeInterval:5.0
                                              block:^{
                                                  __strong ViewController *strongSelf = weakSelf;
                                                  [strongSelf startCounting];
                                              }
                                            repeats:YES];

使用这种方案就可以防止NSTimer对类的保留,从而打破了循环引用的产生。__strong ViewController *strongSelf = weakSelf主要是为了防止执行块的代码时,类被释放了。在类的dealloc方法中,记得调用[_timer invalidate]

相关文章

网友评论

  • AncientMing:可以,有思路。
  • 不必luo嗦:你好,请问这个方法+ (void)jq_blockInvoke:(NSTimer *)timer 为什么不是对象方法(-)
  • f62da20937b3:直接在timer创建的时候target使用weakSelf是否可行?
    9b8f9fc0c496:因为你仅仅传参而已, timer内部实现的时候会用 id obj = weakself 来强引用weakself, 所以这么做是徒劳的。
    iOS_aFei:同问,为什么不行?
  • a7642f69975b:__strong 那里 直接用self 不就可以了嘛?为什么要先weak 然后在strong呢?
    而block内strong不是又循环引用了嘛
    猴子的救兵520:strongSelf 是 block 内部声明的局部变量,block每次开始执行时才会对self引用+1,执行完毕后,strongSelf自动释放,又会对self引用-1。所以没有循环引用。
  • 8ae158dda3f2:好高端
  • 代码干货:不知道是否有用先收藏,日后在试
  • 十一岁的加重:学习了,收藏备用

本文标题:警惕使用NSTimer时的循环引用

本文链接:https://www.haomeiwen.com/subject/cipocttx.html