【问题标题】:ARC, self and blocksARC,自我和块
【发布时间】:2014-03-12 00:20:41
【问题描述】:

我以为我理解在复制的块中使用 self 是 no no

但为了清理我的代码,我在 Xcode 中启用了一堆警告,称为“向弱指针发送消息”

所以现在在我所有的块中,每次我使用我创建的 weakself 引用 __weak typeof(self) weakself = self;

我收到此警告:Weak receiver may be unpredictably set to nil

一个简单的例子:

__weak typeof(self) weakself = self;
[aClass doSomethingInABlock:^{

     [weakself doSomething]; //warning.

}];

我已经看到在块中定义 self 版本的答案,如下所示:

__weak typeof(self) weakself = self;
[aClass doSomethingInABlock:^{
     typeof(self) selfref = weakself; 
     [selfref doSomething]; //no warning.

}];

所以我想知道这里到底发生了什么:

  • 我只是在欺骗编译器吗?
  • 强引用对弱引用有什么作用?
  • 我还缺少什么。

谢谢。

【问题讨论】:

    标签: ios objective-c automatic-ref-counting objective-c-blocks retain-cycle


    【解决方案1】:

    我以为我理解在一个块中使用 self 是不行的。

    这并不完全正确。块保留其中的对象,所以不要在块中使用self如果你的块被self保留

    例如,您可以在 UIView 动画块中使用 self。这是因为您的视图控制器(或任何调用动画的代码)没有指向 UIView 动画块的指针。)

    我只是在欺骗编译器吗?

    没有。

    强引用对弱引用有什么作用?

    如果弱引用不是nil,则增加receiver的retain count。这将阻止对象在您使用时被释放。

    请记住,当不再有对对象的强引用时,ARC 将解除分配对象。通过在块内创建一个强引用,您可以防止可能的释放,直到您完成它。

    我还缺少什么。

    我建议阅读高级内存管理编程指南的Practical Memory Management section。特别是,请阅读“使用弱引用避免保留周期”小节。

    【讨论】:

    • @nils 不,第一种方法(生成警告)是错误的。由于 Avt 在我下面的单独答案中说明了这个问题,因此我不会在这里重复它。
    • (我在这里故意天真和争论不休)但是拥有typeof(self) selfref = weakself; 是否没有在块内建立一个 self 的保留循环?因为我(现在)强烈引用和增加 self 的保留计数?
    • @cream-corn 增加块的保留计数 inside 很好,因为变量是本地范围的 - 当它超出范围时,保留计数将由 ARC 递减(在块的末尾)。如果你只是从块的外部传入self,它不会在最后递减。
    • ...啊哈!我原本是这么想的。感谢您的帮助。
    【解决方案2】:

    请记住,在 ARC 中,只要有 strong 引用,就不会释放对象。

    当一个对象有弱引用时,该对象可能会被释放(如果没有其他强引用对同一对象),因此弱引用并不能确保对象的生命。

    通过这样做:

    typeof(self) selfref = weakself; 
    

    您要确保在使用该对象之前有一个 strong 引用(selfref 是指向同一对象的强引用 weakself 所指的对象)。如果您不这样做,对象可能在您使用时被释放。

    【讨论】:

      【解决方案3】:

      强引用弱引用保留对象。在以下情况下可能很重要

      __weak typeof(self) weakself = self;
      [aClass doSomethingInABlock:^{
      
           [weakself allocateSomething]; // (1)
           // ..... code (2)
           [weakself freeSomething];  // (3)
      }];
      

      如果在第 (2) 行中,Weak 接收器不可预测地设置为 nil,则资源可以在 (1) 中成功分配,但在 (3) 中无法释放。为避免此类问题,可以使用强参考。

      [aClass doSomethingInABlock:^{
           typeof(self) selfref = weakself; 
           [selfref allocateSomething]; // (1)
           // ..... code (2)
           [selfref freeSomething]; // (3)
      }];
      

      现在,如果 selfref 在 (1) 中不为零,它在 (2) 和 (3) 中也有效。

      【讨论】:

      • +1。不切换到强引用是导致难以重现的崩溃的秘诀。 (另一个例子:某些代码在某些时候将weakself 添加到NSArray;如果weakself 为nil,这可能会引发异常。)
      猜你喜欢
      • 2014-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-07
      • 1970-01-01
      • 2012-07-27
      • 2013-07-10
      相关资源
      最近更新 更多