美文网首页iOS开发知识小集iOS面试&笔试
解决NSTimer循环引用的三种方法

解决NSTimer循环引用的三种方法

作者: 二营长开炮 | 来源:发表于2019-04-12 14:21 被阅读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的循环引用还是断开强引用的其中一环
    根据需求择优选择合适的方法

    相关文章

      网友评论

        本文标题:解决NSTimer循环引用的三种方法

        本文链接:https://www.haomeiwen.com/subject/dyfxwqtx.html