如何打破NSTimer 与 Target之间形成的Retain Cycle

NSTimer

NSTimerFoundation框架中一种很方便很有用的对象,开发者可以:

  • 指定绝对的日期和时期,以便到时执行指定任务
  • 指定执行任务的相对延迟时间
  • 指定重复运行的任务

计时器要和run loop(运行循环)相关联,run loop到时候会触发任务。创建NSTimer时,可以将其预先安排在当前run loop中,也可以先创建好,然后手动调用加入run loop中,它才能正常触发任务。

系统方法:

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval
                                     target:(id)target
                                   selector:(SEL)aSelector
                                   userInfo:(nullable id)userInfo
                                    repeats:(BOOL)repeats;

直接创建个实例对象,并将其加入当前run loop当中。

由于计时器会保留目标对象target,所以反复执行任务通常会导致应用程序问题。也就是设置重复执行模式的那种计时器,很容易引入retain cycle(保留环)。

如何打破Retain Cycle

  • 1.MSWeakTimer
  • 2.为NSTimer添加个handlerBlock

推荐方法1,MSWeakTimer

线程安全的Timer,不会对target进行retain操作,支持GCD Queue,NSTimer的替代品

MSWeakTimer现已支持Pod,具体实现及用法请点击这里

下面主要谈谈第二种,如何自己实现来打破retain cycle
1.为NSTimer添加一个Category方法
NSTimer+WeakTimer.h

+ (NSTimer *)zx_scheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval
                                       repeats:(BOOL)repeats
                                  handlerBlock:(void(^)())handler;

NSTimer+WeakTimer.m

+ (NSTimer *)zx_scheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval
                                       repeats:(BOOL)repeats
                                  handlerBlock:(void(^)())handler
{
    return [self scheduledTimerWithTimeInterval:timeInterval
                                         target:self
                                       selector:@selector(handlerBlockInvoke:)
                                       userInfo:[handler copy]
                                        repeats:repeats];
}

+ (void)handlerBlockInvoke:(NSTimer *)timer
{
    void (^block)() = timer.userInfo;
    if (block) {
        block();
    }
}

2.如何使用这个Category方法

  • 创建一个NSTimer
- (void)startPolling
{
    __weak typeof(self)weakSelf = self;
    self.timer = [NSTimer zx_scheduledTimerWithTimeInterval:5.0 repeats:YES handlerBlock:^void(void){
        __strong typeof(weakSelf)strongSelf = weakSelf;
        [strongSelf doPolling];
    }];
}
  • 执行轮询任务slector
- (void)doPolling
{
    //Todo...
}
  • 销毁NSTimer对象
- (void)stopPolling
{
    [self.timer invalidate];
    self.timer = nil;
}

- (void)dealloc
{
    [self.timer invalidate];
}

计时器现在的targerNSTimer类对象。这段代码先是定义了个弱引用,令其指向self,然后block捕获这个引用,而不直接去捕获普通的self变量,也就是说self不会为计时器所保留。当block开始执行时,立刻生成strong强引用,以保证实例在执行期间持续存活,不被释放。

采用这种写法后,外界指向NSTimer的实例最后一个引用被释放后,则创建NSTimer的实例也随之被系统回收。


Refer: Effective Objective-C 2.0 Tips52

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值