美文网首页
NSTimer以及循环引用问题

NSTimer以及循环引用问题

作者: HJ_Technology | 来源:发表于2018-12-11 17:10 被阅读0次

NSTimer

@property (nonatomic, strong) NSTimer *timer;

- (void)viewDidLoad {
    [super viewDidLoad];
    self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerStartMethord) userInfo:nil repeats:YES];
}

- (void)timerTest{
    NSLog(@"%s",__func__);
}

- (void)dealloc{
    [self.timer invalidate];
}

上面这段代码控制器和定时器都是不会释放的。

原因:

  1. 在类拓展中控制器对当前的定时器进行了强引用,在控制器的viewDidLoad方法里面,timer的创建又对控制器进行的强引用(Target参数)。造成了循环应用。控制器和定时器都不会进行释放 。


    image.png

解决方案:

  1. 将控制器对当前timer进行弱引用
    @property (nonatomic, weak) NSTimer *timer;
    image.png
    虽然现在VC对timer进行了弱引用,但是VC和timer还是不能释放,因为runloop对timer进行强引用,timer对VC进行了强引用。
2.所以 我们准备建造一个中间变量,图形结构大致为下面这样 WeChatb0abac673c1dda76c9df1bb986123a39.png

所以我们声明中间变量 HJProxy

@interface HJProxy : NSObject

@property (nonatomic, weak) id target;
+ (instancetype)proxyWithTarget:(id)target;

@end
+ (instancetype)proxyWithTarget:(id)target{
    HJProxy *proxy = [[HJProxy alloc] init];
    proxy.target = target;
    return proxy;
}

- (id)forwardingTargetForSelector:(SEL)aSelector{
    return self.target;
}

//- (NSMethodSignature *)methodSignatureForSelectlor:(SEL)aSelector{
//
//}

//- (void)forwardInvocation:(NSInvocation *)anInvocation{
//
//}

///<  利用消息转发机制将消息转发出去
///<  1. 去方法列表中搜索方法(self super)
///<  2. 找不到进入动态方法解析阶段
///<  3. 动态方法解析找不到 就进入消息转发阶段
///<  4. 先调用forwardingTargetForSelector这个方法,
///<   如果这个方法你没有返回值的话,调用methodSignatureForSelector, 最后调用forwardInvocationl

所以我们调用timer 的方法就变成

     self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:[HJProxy proxyWithTarget:self] selector:@selector(timerStartMethord) userInfo:nil repeats:YES];
}

这样就能像我上面展示的那个图一样,避免循环引用

3.中间变量改造 NSProxy
我们上面的中间变量是继承自NSObject,但是我们这里的中间变量将继承NSProxy


@interface HJProxyProxy : NSProxy

+ (instancetype)proxyWithTarget:(id)target;

@property (nonatomic, weak) id target;

@end

///< NSProxy 本身就没有Init方法,所以直接调用alloc 分配内存就可以了
///< NSProxy 这个类存在的意义就是就来解决 代理行为 ,转发行为

+ (instancetype)proxyWithTarget:(id)target{
    HJProxyProxy *proxy = [HJProxyProxy alloc];
    proxy.target = target;
    return proxy;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{ ///< 返回方法签名
    return [self.target methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation{  ///< 调用
    [invocation invokeWithTarget:self.target];
}

那这两个中间类的方法的区别在哪里

  1. NSProxy 比 NSObject 的效率高,因为 NSObject 里面进行的消息转发,自己类中没有方法的话,他会去父类中找,但是NSProxy他是一步到位,他自己类中如果没有方法,他是不需要去父 类中搜索方法的,
    直接进入消息转发调用methodSignatureForSelector , 相当于节省了去父类搜索的这个流程。

相关文章

网友评论

      本文标题:NSTimer以及循环引用问题

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