【问题标题】:Understanding retain count with the blocks accessing self inside it.了解保留计数与访问自身内部的块。
【发布时间】:2015-01-02 13:44:00
【问题描述】:

我对块的弱引用有基本的了解。我面临的问题是,

每当我在块内访问 self 时,self 的保留计数就会增加 2,而当我在默认块内访问 self 时(例如 UIViewAnimation)自己的保留计数增加了 1。

只是想了解为什么它会增加 2。

提前致谢!

【问题讨论】:

  • 该块将希望保留“捕获的”iVar(如 self)以确保引用保持有效......即self 在执行之前不会解除分配。你会在这里找到很好的信息(MRC 和 ARC 的不同处理。stackoverflow.com/questions/19227982/using-block-and-weak
  • 也是为了更好地理解弱读dhoerl.wordpress.com/2013/04/23/…
  • @YvesLeBorg 感谢分享链接。我只是在检查特定情况下块的行为,它转到 2。
  • 当 ARC 运行时,查看保留计数绝对没有意义。它只会让你感到困惑。您可以从任何保留计数中得出的结论很少,并且在涉及 ARC 时根本没有有效的结论。

标签: ios objective-c iphone objective-c-blocks weak-references


【解决方案1】:

根据Clang源码生成Objective-C块代码。

Objective-C 块字面量由EmitBlockLiteral 函数生成。

llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {

LLVM document 深入解释了什么是块字面量。无论如何,这个函数会生成一个块描述符和一个指定块的复制助手函数。复制助手函数用于捕获自动变量和self

buildBlockDescriptor -> buildCopyHelper -> GenerateCopyHelperFunction

GenerateCopyHelperFunction 函数中,Clang 为每个将被块捕获的 Objective-C 对象自动变量发出 objc_storeStrong

for (const auto &CI : blockDecl->captures()) {
    ...
    EmitARCStoreStrongCall(...

因此,此行将计算 self (1 -> 2) 的保留计数。

之后,EmitBlockLiteral 函数也会为每个将被块捕获的 Objective-C 对象自动变量发出 objc_retain

// Next, captured variables.
for (const auto &CI : blockDecl->captures()) {
    ...
    EmitExprAsInit -> EmitScalarInit -> EmitARCRetain

因此,此行也会计算 self 的保留计数 (2 -> 3)。

我不知道确切的原因。但显然,在块复制辅助函数捕获对象之前保留 Objective-C 对象是有原因的。

【讨论】:

    【解决方案2】:

    在块中使用 self 通常会创建一个循环,这可能是它增加 2 的原因。要解决此问题,您应该尝试使用弱 self。看看这个问题

    capturing self strongly in this block is likely to lead to a retain cycle

    使用类似的东西
    __unsafe_unretained typeof(self) weakSelf = self;

    【讨论】:

    • 在块内使用self 不会创建循环。它创建从块到self 的引用。如果您创建一个循环,它只会创建一个循环 - 如果您保留从 self 到该块的引用。这不是这里发生的事情。
    猜你喜欢
    • 2017-12-19
    • 1970-01-01
    • 2016-09-26
    • 1970-01-01
    • 2020-08-31
    • 2012-01-03
    • 1970-01-01
    • 1970-01-01
    • 2011-05-03
    相关资源
    最近更新 更多