【问题标题】:In Objective-C, what does it mean to assign a weak to a strong within a block?在 Objective-C 中,在块内将弱分配给强是什么意思?
【发布时间】:2014-01-04 04:33:47
【问题描述】:

在 Objective-C 中,将 weak 分配给块内的 strong 是什么意思?幕后发生了什么?

例如

__weak __typeof(self) wself = self;

void (^cmd)() = ^(){
    __strong __typeof(self) sself = wself;
    if (!sself) return;
    ...
};

【问题讨论】:

  • 对此不太确定,但我认为将弱分配给强是添加对对象的引用的逻辑,因为弱不会使引用的对象保持活动状态,并且当有重复时它会产生一个新的参考...
  • 我有一些非常复杂的网络代码,同时使用了强自我和弱自我,我写了一篇关于它的博客,可能会更清楚:dhoerl.wordpress.com/2013/04/23/…
  • @DavidH 好一波恩也看看stackoverflow.com/questions/11013587/…
  • @Rob,谢谢,已编辑。

标签: objective-c automatic-ref-counting objective-c-blocks


【解决方案1】:

这里的意图有两个:

  1. 首先是使用:

    __weak __typeof(self) wself = self;
    

    这可确保cmd 块不会保持对self 的强引用。这样可以确保,如果 cmd 是类的实例变量,那么您不会以强引用循环告终。如果你不使用这个wself 模式,那么以cmd 作为实例变量的类将永远不会被释放,并且你会泄漏以cmd 作为实例变量的对象。

    有关详细信息,请参阅Objective-C 编程:使用块文档的Avoid Strong Reference Cycles when Capturing self 部分。

  2. 二、块内使用如下:

    __strong __typeof(self) sself = wself;
    if (!sself) return;
    

    这确保了,如果块开始执行,如果 wself 已经被释放,块将退出。但是如果wself 还没有被释放,通过分配sself,你可以确保在块执行期间对象将被保留。

    此外,如果您引用块中的任何 ivars,请注意您要取消引用它们(因为否则块中会隐含对 self 的引用,可能会导致强引用循环)。但是你不能使用弱指针取消引用 ivars(例如 wself->someIvar 是不允许的),但是你可以使用这个本地强指针(例如 sself->someIvar 可以)。一般来说,无论如何您都不应该取消引用 ivars,而应该使用属性,但这是使用对 self 的本地强引用的另一个原因。

通常,您会看到此构造与类属性(或 ivar)结合使用:

@property (nonatomic, copy) void (^commandBlock)(void);

而且,按照惯例,您通常会看到更具描述性的变量名称,weakSelfstrongSelf,因此:

__weak __typeof(self) weakSelf = self;

self.commandBlock = ^(){
    __strong __typeof(self) strongSelf = weakSelf;
    if (!strongSelf) return;
    ...
};

这种weakSelf/strongSelf 模式在您拥有自己的类的块属性并且想要 (a) 防止强引用循环(也称为保留循环)时非常常见;但是 (b) 想要确保有问题的对象不能在块的执行过程中被释放。

【讨论】:

  • 喜欢知识的分块。谢谢。
  • "通过分配 sself,您可以确保在块执行期间对象将被保留。"我很难看到解除分配是如何实际发生的。通过self 对象或不调用该块。 1) 如果它不是通过self 调用的,那么其他东西必须具有对该块的(强)引用(或保留该块的东西)。所以块(或拥有它的东西)首先作为实例变量存储在self 中,然后在self 死之前将其提供给其他东西以保留。我认为这不是很常见,用户可以轻松检查。
  • 2) 如果它通过self 对象调用(通过一些指向self 对象的指针),那么这类似于在self 对象上调用方法。这是因为,在 ARC 中的方法中,self 未被保留。因此,无论何种情况都可能导致在通过对象调用的块的中间释放分配,也可以类似地发生在通过对象调用的方法的中间,以同样的方式。显然 ARC 的人认为这太不寻常了,他们没有费心保留self
  • @Rob:我没有假设该块是如何运行的。我的意思是,如果网络操作在后台运行并由该后台进程保留,则通常不需要由视图控制器保留。另外,任何更新 UI 的东西都应该在主线程上运行,所以应该不会出现这个问题。
  • @newacct 你误解了我的意思。但也许这并不重要:如果你的观点是竞争条件不太可能,那是真的(但所有竞争条件本质上都是不可能的)。如果你的观点是它永远不会发生,那么我们会同意不同意。但请参阅 Transitioning to ARC RNARC Introduces New Lifetime Qualifiers 部分末尾的 Apple 关于“非平凡循环”的讨论。
【解决方案2】:

如果您不将weak 引用分配给strong,则weak 引用所引用的对象可以在块执行过程中被释放——这是您可能不会想到的。如果你分配给strong,只要强引用在范围内,对象就会被保留(除非在分配之前对象已经被释放)。

当您将弱引用分配给强编译器时,会将 Objective-C 运行时函数调用插入到代码中,该代码会根据需要增加对象引用计数器以保留它。当强变量超出范围时(或更早,在最后一次使用强变量之后)编译器插入的另一个调用会减少引用计数器。

【讨论】:

  • 幕后发生了什么?对 strong 的赋值是否会导致 ref 计数增加?
  • 我不知道 ARC 机制的所有细节(它可能会执行一些优化),但从概念上讲,您可以认为当您将引用分配给强变量时,引用计数器会增加。
  • @Boon 虽然我们不应该再考虑“保留计数”,是的,在块内分配给局部强变量将导致保留计数增加块执行(但不是之前),并且当块完成执行并且sself 变量超出范围时,保留计数将减少。
猜你喜欢
  • 2014-01-31
  • 1970-01-01
  • 2011-09-14
  • 2011-08-01
  • 2010-10-09
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多