【问题标题】:Strong reference to a weak references inside blocks对块内弱引用的强引用
【发布时间】:2014-05-22 12:25:41
【问题描述】:

为什么必须在块内对弱引用进行强引用?

我了解在块内使用弱引用将避免保留循环。但是为什么又要强引用弱呢?

背景:
正如Mason 所述,这是最佳做法。

我知道在块内引用 self 的正确方法是在块外创建一个弱引用,然后在块内创建一个对该弱引用的强引用[...]

示例:

__weak typeof(self) weakSelf = self;
void (^someBlock)(id) = ^(id data){
    typeof(self) strongSelf = weakSelf;
    // code using strongSelf
});

【问题讨论】:

  • 实际上没有必要在块内再次使指针变强。
  • 如果您使用libextobj,则使用@weakify(self)@strongify(self) 是一种更漂亮、更干净的方法
  • 它可能更漂亮,但这不是官方语言的一部分。
  • @holex “实际上没有必要在块内再次使指针变强”。为什么?在块执行的中间,弱指针可能会为零。
  • @BangOperator,那么接下来会发生什么?如果实际对象无论如何都要被释放,那么在大多数情况下,块也会失去它的目的。

标签: ios objective-c objective-c-blocks


【解决方案1】:

想象一下,最后剩下的对 self 的强引用保存在与运行块的线程不同的线程上。

现在发生了:

__weak typeof(self) weakSelf = self;
void (^someBlock)(id) = ^(id data){
    if (weakSelf != nil) {
       // last remaining strong reference released by another thread. 
       // weakSelf is now set to nil.
       [myArray addObject:weakSelf];
    }
});

这将因向数组添加 nil 的 NSInvalidArgument 异常而崩溃。

在使用前使引用变强可以消除潜在的竞争条件并确保指针始终指向同一个对象。

如果您 100% 确定一个对象只会被一个线程引用,则没有必要这样做。但做出这种假设是不好的做法。

【讨论】:

  • 如果您让应用程序在这些情况下崩溃,它会帮助您更轻松地找到错误,了解您在 之前 释放对象的原因和位置,尽管有任何块仍然需要它。
  • 在另一个线程上持有弱引用时允许释放对象是有正当理由的。当然,您可能想要断言指针不是 nil,但是在weakSelf 上这样做会遭受相同的竞争条件。
  • 如果使用弱引用的唯一原因是为了避免保留循环,那么在块执行之前或期间弱引用变为 nil 的任何情况都可以说是错误。
  • 在这种情况下,您仍然希望可以预见地失败。引入竞争条件并不能改善调试体验...
  • @ChrisDevereux 你是男人!这么多解释,这个是最优化的!这对 Swift 也是如此吗?我们在哪里使用捕获列表?如果是,请告诉如何将 [weak self] 转换为 self
【解决方案2】:

这不是本质上必要的,但总体思路是确保在块执行时不会释放weakSelf 指向的对象。创建强引用具有保留对象的副作用。当强引用超出范围时,ARC 将释放该保留。它主要是防御性的。一般来说,您应该致力于提供其他(更好的)保证,以确保您的系统在块执行期间保持稳定。

【讨论】:

    猜你喜欢
    • 2013-09-08
    • 1970-01-01
    • 2013-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多