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];

参考文章

NSTimer循环引用解决方案

如果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));
上一篇 下一篇

猜你喜欢

热点阅读