如果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、通过中间代理对象的方式
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
网友评论