iOS - GCD 对自身的弱引用和强引用

iOS - GCD weak and strong reference to self

当我在 GCD 的一个区块中时,我总是使用 __weak 引用 self。每个人都建议这样做。我知道在 GCD 中对 self(已测试)的强引用不能产生保留周期。 Apple 建议使用 __weak 对自身的引用,然后 __strong_week 引用的引用,以保证 self 不会执行块时 nil

我有如下一段代码:

- (IBAction)startGCD:(id)sender {

    GCDVC* __weak weakSelf = self;

    [self.activityIndicator startAnimating];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ // 1

        // VC2* __strong strongSelf = weakSelf;

        [weakSelf.proArray addObject:@"2"];

        [NSThread sleepForTimeInterval:10];

        NSLog(@"%@",weakSelf.proArray);

        dispatch_async(dispatch_get_main_queue(), ^{ // 2
            [weakSelf.activityIndicator stopAnimating];
        });
    });

}

测试 1 我按下按钮,指示器开始旋转。我在 GCD 完成之前按下后退按钮,GCDViewController 被释放。

测试 2 然后我取消对 self 的强引用的注释并执行相同的过程。 GCDViewController 在块完成工作之前不会被释放。但后来发布了。

测试 3 现在,如果我直接引用 self(没有 __weak__strong),我的行为与测试 2 完全相同。

因此,如果我想确保在执行块时 self 不会为 nil,那么使用 __strong 引用 __weak 引用 [=13= 的意义何在? ]?我在这里想念什么吗?是否有任何示例会改变测试 2 和 3 的结果?

I was always using __weak references to self when I was in a block in GCD. Everyone recommends that.

没有。我不知道有谁推荐这个。在某些存在循环保留的情况下,弱引用是有意义的。但是一个块是否应该捕获对任何对象(包括 self 指向的对象)的弱引用或强引用取决于相关代码的特定内存管理设计和

I know that strong reference to self (tested) in GCD can't produce retain cycles.

在全局或主队列上将块传递给 dispatch_async 永远不会产生保留周期。

Now if I refer directly to self (without __weak or __strong) I have the exact behaviour with Test 2.

在这种情况下,您可能看不出有什么不同。但它们通常有不同的行为。基本上,您的问题是捕获对 self.

指向的对象的强引用或弱引用的块之间有什么区别

不同之处在于,如果当前对象(self 指向的对象)已被持有强引用的所有其他对象释放,除了潜在的块和块之后异步执行。

  • 如果该块捕获了对当前对象的强引用,那么该引用将使该对象在整个时间内保持活动状态。所以对象仍然存在,我们可以使用它并向它发送消息等。
  • 如果块捕获了对当前对象的弱引用,那么当前对象已经被释放,当对它的最后一个强引用被释放时。所以这个块的弱引用在这一点上是 nil,并且这个块不会对它做任何事情(它要么在看到它时检查 strongSelf 和 return是 nil,否则它将向 strongSelf 发送消息,即 nil 什么都不做)。

所以在一种情况下,事情已经完成,而在另一种情况下,什么也没做。

如果您的当前对象是某个 UI 元素,例如视图或视图控制器,那么只要它在视图层次结构中,它就会被视图中的事物保留层次结构,所以你需要退出这个 view/view 控制器,以便没有其他东西对它有强引用。

在你的情况下,你在块内所做的就是 [weakSelf.activityIndicator stopAnimating];,即对 UI 的更改。这个命令是不是运行并不重要,因为,记住,包含这个的视图已经停止显示了。没有人可以看到这个 activity 指标。那么停不停有什么区别呢?但这是特定于这种情况的。一般来说,你可以想象块内的命令改变一些全局状态,或者通过网络发送一些东西什么的,做与不做之间有很大的区别。