iOS开发知识小集iOS面试&笔试

解决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

// 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的循环引用还是断开强引用的其中一环
根据需求择优选择合适的方法

上一篇下一篇

猜你喜欢

热点阅读