iOS开发

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

2023-09-04  本文已影响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

上一篇 下一篇

猜你喜欢

热点阅读