美文网首页iOS
iOS - block中的循环引用

iOS - block中的循环引用

作者: 拾识物者 | 来源:发表于2019-03-25 17:34 被阅读20次

想研究什么是循环引用,就要动手做实验,实验的结果如何验证?也就是如何判断一个对象循环引用了?

验证方法

最简单的办法就是在 dealloc 方法中打印 log,判断一个对象的 dealloc 方法是否调用,如果调用了表示被释放了。再注意要排除干扰,只设置实验对象的引用,不要设置多余的引用会影响计数。

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

什么是循环引用

循环引用的概念很简单,对象之间的强引用链形成了环就创造了一个循环引用。

最简单的情况,两个对象,你引用我,我引用你,就形成了循环引用。再复杂一点不过是多个对象构成一个更大的引用环。

需要注意的是 block 的使用造成的强引用链,block 会捕获内部使用的对象,形成隐式的强引用,一般有以下两种常见的情况:

  • 引用 self:直接写 self。
self.callback = ^{
    NSLog(@"callback: %@", self);
}
  • 成员变量:不写 self,但实际上还是对 self 的强引用
self.callback = ^{
    NSLog(@"callback: %@", _name);
    // 等价于
    NSLog(@"callback: %@", self->_name);
}

使用 weak 解除强引用

核心方法只有一个,就是用 weak 引用解除 strong 引用。各种方案的不同之处在于什么时候定义 weak 应用。

直接定义属性为 weak 类型:

@property (weak, nonatomic) id<RadarNodeDelegate> delegate;

让 block 捕获 weak 引用替代捕获 strong 引用:

__weak typeof(self) weakSelf = self;
self.callback = ^() {
    NSLog(@"callback: %@", weakSelf.name);
}

由于弱引用指向的对象在使用的时候可能已经被回收了,被回收后弱引用会自动指向 nil。

__weak typeof(self) weakSelf = self;
self.callback = ^() {
    NSLog(@"callback: %@", weakSelf ? weakSelf._name : @"???");
}

上面这段代码是有一些安全隐患的,因为 weakSelf 被使用了两次,在两次使用之间,weakSelf 指向的对象可能会释放,会导致不一致的情况。

不过这也不是肯定会发生的,还要看执行 callback 的线程和 执行 dealloc 的线程是否相同,如果相同肯定不会发生这种情况,要么在执行 callback 的时候 weakSelf 已经指向了 nil,要么在执行 callback 的时候 weakSelf不会被释放。

dealloc 执行的线程并不一定是主线程,或者某个固定的线程,而是最后一个由自动引用计数释放它的线程。在多个线程中使用一个对象肯定会产生这种隐患。

因此另一个方法用来避免这种情况:

__weak typeof(self) weakSelf = self;
self.callback = ^() {
    __strong typeof(self) strongSelf = weakSelf;
    NSLog(@"callback: %@", strongSelf ? strongSelf.name : @"???");
}

使用 __strong 关键字将弱引用转换为强引用,这个操作是原子操作,结果要么是 nil 要么指向了对象。一旦指向了对象,由于是强引用,就保证了对象不会被释放掉,又由于是局部引用,一旦退出作用域,如果只剩下这个引用就会释放引用。既保证了使用过程中不会突然变成 nil,也保证在执行结束后正确释放掉。

有的文章说 strong 化引用的目的是防止被释放,这个说法是片面的,如果在 strong 化的代码之前,也就是进入 block 之前就被释放了,那么 strong 引用的值也是 nil。它的作用在于解决 block 内部使用多次弱引用对象有可能不一致的问题,而不是保证该对象在执行 block 之前不被释放。

(ole)

相关文章

  • iOS复习之Block

    iOS面试中如何优雅回答Block iOS block循环引用

  • Block循环引用问题

    IOS中block循环引用现象:例如: 判断方法: 解决方法:

  • NSTimer的循环引用问题解决方案

    iOS开发中,针对循环引用的问题,会有很多方面,block,代理,自循环,多循环,还有一个就是Timer的循环引用...

  • iOS Block __block说明符

    系列文章:iOS Block概念、语法及基本使用iOS Block实现原理iOS Block存储域及循环引用 上一...

  • iOS - block中的循环引用

    想研究什么是循环引用,就要动手做实验,实验的结果如何验证?也就是如何判断一个对象循环引用了? 验证方法 最简单的办...

  • iOS 循环引用

    关于循环引用看着3篇文章就够了,拿走不谢! 循环引用 循环引用 OC中的block OC中的block 关于 bl...

  • Block循环引用的四种解决方案

    Block常见的循环引用模型 以下是常见的Block循环引用模型,self引用block,block引用self,...

  • IOS基础Block

    参考: iOS中block的使用、实现底层、循环引用、存储位置 一:Block的使用格式和用途 1,声明和定义格式...

  • __block与__weak的真正区别

    block下循环引用的问题 __block本身并不能避免循环引用,避免循环引用需要在block内部把__block...

  • __block和__weak修饰符的区别

    block下循环引用的问题 __block本身并不能避免循环引用,避免循环引用需要在block内部把__block...

网友评论

    本文标题:iOS - block中的循环引用

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