警惕使用NSTimer时的循环引用

使用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]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 37.cocoa内存管理规则 1)当你使用new,alloc或copy方法创建一个对象时,该对象的保留计数器值为1...
    如风家的秘密阅读 887评论 0 4
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,896评论 18 139
  • NSTimer 计时器是一种很方便的对象。Foundation 框架中有个类叫做NSTimer,开发者可以指定绝对...
    KKLinJJ阅读 676评论 0 1
  • 文/Jack_lin(简书作者)原文链接:http://www.jianshu.com/p/5d2163640e2...
    笔笔请求阅读 559评论 0 0
  • 命运有自己的时间表,一切都是自然而然。顺其自然,我从来不给自己定期限。—朴树 曾视为珍宝的某些情怀统统一触即发,这...
    Stronggirl阅读 721评论 0 0