iOS开发系列-定时器强引用问题

概述

iOS开发中常用的定时器NSTimerCADisplayLink

NSTimer的创建方法有两个scheduledTimerWithTimeInterval开头另一个直接timerWithTimeInterval

// scheduled开头创建的定时器默认已经添加到RunLoop中
self.timer =[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(testTimer) userInfo:nil repeats:YES];

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(testTimer) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

CADisplayLink创建方法displayLinkWithTarget创建

CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(testLink)];
[link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

定时器强引用问题

在开发中在将通常将控制器作为定时器的target。一般我们在控制器的dealloc方法中停止定时器。

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

由于将控制器设置为定时器的target,定时器会对控制器做强引用,造成控制器在pop出栈不会销毁,也不会调用控制器的的dealloc的方法,控制器pop后,定时器依然执行。

避免设置target强引用解决方案

方案一

由于NSTimer可以通过block的方式直接设置定时任务可以避免设置target引起的强引用。

[NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        // 定时任务
}];

方案二

创建一个代理TimerProxy,将代理作为定时器target。

TimerProxy.h

#import <Foundation/Foundation.h>

@interface HTTimerProxy : NSObject
+ (instancetype)timerProxyWithTaget:(id)target;
@property (nonatomic, weak) id target;
@end

TimerProxy.m

#import "HTTimerProxy.h"

@implementation HTTimerProxy

+ (instancetype)timerProxyWithTaget:(id)target
{
    HTTimerProxy *proxy = [[self alloc] init];
    proxy.target = target;
    return proxy;
}

// 利用runtime的消息转发
- (id)forwardingTargetForSelector:(SEL)aSelector
{
    return self.target;
}
@end

NSTimer与CADisplayLink将HTTimerProx作为代理

// scheduled开头创建的定时器默认已经添加到RunLoop中
self.timer =[NSTimer scheduledTimerWithTimeInterval:1.0 target:[HTTimerProxy timerProxyWithTaget:self] selector:@selector(testTimer) userInfo:nil repeats:YES];

CADisplayLink *link = [CADisplayLink displayLinkWithTarget:[HTTimerProxy timerProxyWithTaget:self] selector:@selector(testLink)];
[link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
原文地址:https://www.cnblogs.com/CoderHong/p/9389753.html