NSTimer引用循环 2019-11-05
2019-11-05 本文已影响0人
勇往直前888
问题
采用如下方法使用定时器会导致引用循环:
self.timer = [NSTimer timerWithTimeInterval:0.02 target:self selector:@selector(moveLineImageView) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
WeakSelf失效
既然是强引用导致循环引用,那么用__weak
修饰self
就好了,想法是对的,但是做法是无效的。因为无论是weak
还是strong
修饰,在NSTimer
中都会重新生成一个新的强引用指针指向self,导致循环引用的。
WeakProxy方式
解决方法有好多种,这次采用了弱代理的方案。
WeakProxy.h文件
@interface WeakProxy : NSProxy
// 初始化接口
+ (instancetype)proxyWithTarget:(id)target;
@end
WeakProxy.m文件
#import "WeakProxy.h"
@interface WeakProxy ()
@property (weak, nonatomic, readonly) id weakTarget;
@end
@implementation WeakProxy
// 初始化接口
+ (instancetype)proxyWithTarget:(id)target {
return [[self alloc] initWithTarget:target];
}
// 初始化
- (instancetype)initWithTarget:(id)target {
_weakTarget = target;
return self;
}
#pragma mark - 重写方法
// 改变调用对象,也就是说,让消息实际上发给真正的实现这个方法的类
- (void)forwardInvocation:(NSInvocation *)invocation {
SEL sel = [invocation selector];
if ([self.weakTarget respondsToSelector:sel]) {
[invocation invokeWithTarget:self.weakTarget];
}
}
// 返回方法的签名。
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.weakTarget methodSignatureForSelector:sel];
}
- (BOOL)respondsToSelector:(SEL)aSelector {
return [self.weakTarget respondsToSelector:aSelector];
}
@end
VC调用
self.timer = [NSTimer timerWithTimeInterval:0.02 target:[WeakProxy proxyWithTarget:self] selector:@selector(moveLineImageView) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
参考文章
如果iOS10
估计苹果也感觉太差了,iOS10增加了block版本的计时器,就不存在这个问题了。
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));