美文网首页iOS开发
关于Block中的非典型循环引用

关于Block中的非典型循环引用

作者: 高浩浩浩浩浩浩 | 来源:发表于2023-09-04 12:12 被阅读0次

今天遇到这样子一个场景,嵌套Block下的外层strongSelf是否会产生循环引用
先看Demo 代码:

- (void)testRetainCycle {
    __weak typeof(self) weakSelf = self;
    NSLog(@"B objc doStudent strong-----retainCount : %lu", CFGetRetainCount(((__bridge CFTypeRef)self)));

    self.doWork = ^{
        __strong typeof(self) strongSelf = weakSelf;
        NSLog(@"B objc doStudent strong-----retainCount : %lu", CFGetRetainCount(((__bridge CFTypeRef)strongSelf)));

        weakSelf.doStudent = ^{
            NSLog(@"B objc doStudent strong-----retainCount : %lu", CFGetRetainCount(((__bridge CFTypeRef)strongSelf)));
        };
        weakSelf.doStudent();
    };
    self.doWork();
}

先说结论: 这里会产生循环引用的
并且是self和doStudent互相持有导致的循环引用。
从memory graph 上看也确实是这样子:

Xnip2023-09-05_11-12-54.jpg

那么为什么呢?我们知道在ARC中:

__weak:

  1. __weak用于声明弱引用,不会增加对象的引用计数。这是为了避免循环引用问题,常用于解决持有对象之间的强引用循环。
  2. 如果一个对象只有__weak引用,当没有强引用指向它时,对象会被释放,这可以防止循环引用。

但是当我们在Block里面去用StrongSelf去持有一个weak引用的时候,会导致weak的引用计数+1,这么做一般是用来避免block内的对象被提前释放。

那我们再回到这个代码里面, 在这里

__strong typeof(self) strongSelf = weakSelf;

weakSelf的引用计数+1, 可以理解为这里的doWork 持有了 strongSelf/ weakSelf。

那么在weakSelf被+1的情况, 那么doStudent也被doWork持有了。

那么引用关系就出现了, doStudent 里面又持有了 strongSelf。

本来正常的情况是在doWork执行完成以后释放strongSelf的, 但是因为strongSelf被doStudent 持有了无法释放。

weakSelf持有了doStudent, 因为weakSelf没有释放,所以doStudent 也无法释放了。
这里形成了循环引用。

下面是解决办法:
- (void)testRetainCycle {
    __weak typeof(self) weakSelf = self;
    NSLog(@"B objc doStudent strong-----retainCount : %lu", CFGetRetainCount(((__bridge CFTypeRef)self)));

    self.doWork = ^{
        __strong typeof(self) strongSelf = weakSelf;
        NSLog(@"B objc doStudent strong-----retainCount : %lu", CFGetRetainCount(((__bridge CFTypeRef)strongSelf)));

        weakSelf.doStudent = ^{
            __strong typeof(self) strongSelf2 = weakSelf;
            NSLog(@"B objc doStudent strong-----retainCount : %lu", CFGetRetainCount(((__bridge CFTypeRef)strongSelf2)));
        };
        weakSelf.doStudent();
    };
    self.doWork();
}

这里在内层用另一个临时变量去引用weak,可以解决循环引用,从这里也能看出来循环引用的持有原因

PS:这里用memory graph调试 内存问题真的很好用

Using Xcode’s memory graph to find memory leaks

相关文章

  • iOS 循环引用

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

  • Block循环引用

    循环引用:你引用我,我引用你, 双方都不会销毁, 造成内存泄漏。 关于Block需知: Block会对代码块中的所...

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

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

  • __block与__weak的真正区别

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

  • __block和__weak修饰符的区别

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

  • __block与__weak的区别

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

  • Block循环引用的两种情况(self和私有成员变量)

    Block的循环引用问题非常常见 1、Block 内部引用 self,造成循环引用 (1)这种 Block 循环引...

  • block N连问

    Block 与 循环引用 1、 在所有的Block中,使用self 都会引起循环引用吗? 答:不一定.循环引用的原...

  • __block 和__ weak 的区别

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

  • iOS开发 循环引用的几种场景

    delegate 循环引用如果delegate使用strong修饰容易引起循环引用 block 循环引用block...

网友评论

    本文标题:关于Block中的非典型循环引用

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