解决NSTimer循环引用的三种方法
2019-04-12 本文已影响46人
二营长开炮
总结一下项目中遇到的NSTimer循环引用问题
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
上述方法NSTimer作为属性时会产生循环引用问题,weakself修饰也并不会解决循环引用问题,我猜测在NSTimer内部,传进去的target被NSTimer强引用
@property (nonatomic, strong) id aTarget;
三种方法解决循环引用问题
第一种做法:
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
// weakSelf.
}];
第二种做法:设置一个中间商继承于NSObject,利用消息转发机制
在.h文件中
+ (instancetype)middleManWithTarget:(id)target;
// 在这里用weak
@property (weak, nonatomic) id target;
在.m文件中
+ (instancetype)middleManWithTarget:(id)target
{
MiddleMan *middleMan = [[MiddleMan alloc] init];
middleMan.target = target;
return middleMan;
}
- (id)forwardingTargetForSelector:(SEL)aSelector
{
return self.target;
}
第三种做法:设置一个不赚差价的中间商继承于NSProxy
- NSProxy对象不需要调用init,因为它本来就没有init方法
- 没有消息转发的forwardingTargetForSelector方法,直接进行消息转发,因为NSProxy类和NSObject一样相当于都是基类,只会寻找自己不会去父类寻找,相当于没有父类,少了动态方法解析和去父类寻找的过程
这个效率比较高,专门做消息转发
// NSObject底层结构
@interface NSObject {
Class isa OBJC_ISA_AVAILABILITY;
}
// NSProxy底层结构
@interface NSProxy {
Class isa;
}
在MyProxy.h中(创建的继承于NSProxy的类)
+ (instancetype)proxyWithTarget:(id)target;
@property (weak, nonatomic) id target;
在MyProxy.m中
+ (instancetype)proxyWithTarget:(id)target
{
// NSProxy对象不需要调用init,它没有init方法
MyProxy *proxy = [MyProxy alloc];
proxy.target = target;
return proxy;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
// 返回方法签名
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
// 方法签名不为空来到此方法
[invocation invokeWithTarget:self.target];
}
其实解决NSTimer的循环引用还是断开强引用的其中一环
根据需求择优选择合适的方法