在ARC下,当直接分配给实例变量时,块是否会自动复制?

20
假设以下代码是在 ARC 下编写的:
typedef void (^MyResponseHandler) (NSError *error);
@interface MyClass : NSObject
{
    MyResponseHandler _ivarResponseHandler;
}

- (void)myMethod:(MyResponseHandler)responseHandler
{
    _ivarResponseHandler = responseHandler;
    ...
}

问题:当将块分配给实例变量时,它是否自动复制到堆上? 我之前的问题暗示了通过@property分配时会被复制。但是,今天我使用了上面的代码并收到了一个EXC_BAD_ACCESS,通过更改为_ivarResponseHandler = [responseHandler copy]修复了该问题。
2个回答

10

编辑:我的之前的答案可能是错误的。

以下是来自ARC文档的部分摘录:

3. 可保留对象指针

可保留对象指针(或保留指针)是一种可保留对象指针类型(保留类型)的值。有三种可保留对象指针类型:

  • 块指针(通过将脱字符 (^) 声明符附加到函数类型形成)

4.2. 语义

赋值发生在求值赋值运算符时。语义因资格而异:

  • 对于 __strong 对象,首先保留新 pointee;其次,使用基元语义加载 lvalue;第三,使用基元语义将新 pointee 存储到 lvalue 中;最后,释放旧 pointee。这不是原子执行的;必须使用外部同步来使其在并发加载和存储的情况下安全。

4.4.1. 对象

如果一个对象声明为具有可保留对象所有者类型,但没有显式的所有权限定符,则其类型会被隐式调整为具有 __strong 限定符。

7.5. 块

除了作为初始化 __strong 参数变量或读取 __weak 变量的一部分进行保留之外,每当这些语义要求保留块指针类型的值时,它具有 Block_copy 的效果。当优化器看到结果仅用作调用的参数时,可以删除此类副本。

因此,我的答案是可能,具体取决于优化器。


你知道我是在参考自动引用计数环境吗?在ARC中,你的foo/bar示例似乎不会有问题...? - bearMountain
抱歉,你的回答或提供的苹果文档并没有说明当分配给实例变量时,ARC是否会自动将块移动到堆中。看来这个问题的答案将不得不来自于clang Objective-C自动引用计数文档 - bearMountain
2
感谢所有的努力Sbooth。哇,这份文档真难懂。实际上,我会认为编译器会插入一个Block_copy。似乎ivar默认为__strong,因此赋值将“调用保留block指针类型的值”,从而插入Block_copy。虽然想得到一个明确的答案,但现在我想先把块存储在@property(copy)中。 - bearMountain

4
您的问题和解决方案表明,我对您另一个问题的答案可能是错误的。我基于clang Objective-C Automatic Reference Counting documentation第7.5节的最后一段进行了推断:

除了作为初始化参数变量或读取弱引用变量的一部分而执行的保留之外,每当这些语义要求保留块指针类型的值时,它具有Block_copy的效果。优化器可以在看到结果仅用作调用参数时删除这些副本。

我认为“这些语义”是指整个文档,但如果“这些语义”仅指第7.5节,则ARC仅为被块捕获的块插入Block_copy


我同意,“这些语义”指的是什么并不清楚。 - sbooth
3
我和撰写这一部分的苹果工程师进行了交谈,他说“这些语义”指的是整个文档。因此应该自动插入 Block_copy。看起来这可能是早期块存在的错误,后来得到了修复。 - bearMountain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接