iOS定时器 NSTimer、CADisplayLink循环引用问题

如果CADisplayLink、NSTimer对target强引用,同时target又对CADisplayLink、NSTimer强引用,那么此时就会引发循环引用!

@property(nonatomic,strong) CADisplayLink *displayLink;//self强引用了CADisplayLink

// CADisplayLink内部又强引用了self
self. displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(linkTest)];
[self. displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

- (void)linkTest {

    NSLog(@"%s",__func__);
}

- (void)dealloc {//循环引用导致dealloc方法不会被调用

    NSLog(@"%s", __func__);
    [self. displayLink invalidate];
}

同理下面NSTimer也是这种情况

@property (strong, nonatomic) NSTimer *timer;

self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTest) userInfo:nil repeats:YES];

- (void)timerTest {

   NSLog(@"%s", __func__);
}

- (void)dealloc {
   NSLog(@"%s", __func__);
   [self.timer invalidate];
}

解决方案

1、使用NSTimer的类方法,并弱引用self
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {

      [weakSelf timerTest];
}];
2、通过中间代理对象的方式
iOS定时器 NSTimer、CADisplayLink循环引用问题_第1张图片
1728484-4406c7791f5339c3.png
@interface ZCMiddleProxy : NSObject

//此处用weak修饰
@property (nonatomic, weak) id target;

+ (instancetype)proxyWithTarget:(id)target;

@end


#import "ZCMiddleProxy.h"

@implementation ZCMiddleProxy

+ (instancetype)proxyWithTarget:(id)target {

   ZCMiddleProxy *proxy = [[ZCMiddleProxy alloc] init];
   proxy.target = target;
   return proxy;
}

// 消息转发机制(会先发送消息、再动态解析、最后再消息转发)
- (id)forwardingTargetForSelector:(SEL)aSelector {

    return self.target;
}
@end
//timer改为这么使用,就可以解决循环引用问题
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[ZCMiddleProxy proxyWithTarget:self] selector:@selector(timerTest) userInfo:nil repeats:YES];

参考链接:https://www.jianshu.com/p/524bc26855d3

你可能感兴趣的:(iOS定时器 NSTimer、CADisplayLink循环引用问题)