【发布时间】:2012-02-08 03:31:27
【问题描述】:
考虑以下代码:
@interface ClassA : NSObject
@property (nonatomic, copy) void(^blockCopy)();
@end
@implementation ClassA
@synthesize blockCopy;
- (void)giveBlock:(void(^)())inBlock {
blockCopy = inBlock;
}
@end
然后在具有ClassA 类型的strong 属性称为someA 的类中使用它:
self.someA = [[ClassA alloc] init];
[self.someA giveBlock:^{
NSLog(@"self = %@", self);
}];
dispatch_async(dispatch_get_main_queue(), ^{
self.someA.blockCopy();
self.someA = nil;
});
如果我在启用 ARC 的情况下运行构建的 O3,在 iOS 上,它会在 objc_retain 内部的 self.someA.blockCopy(); 调用期间崩溃。为什么?
现在我意识到人们可能会说我应该使用self.blockCopy = inBlock 进行设置,但我确实认为 ARC 应该在这里做正确的事情。如果我查看由giveBlock: 方法生成的程序集(ARMv7),它看起来像这样:
.align 2
.code 16
.thumb_func "-[ClassA giveBlock:]"
"-[ClassA giveBlock:]":
push {r7, lr}
movw r1, :lower16:(_OBJC_IVAR_$_ClassA.blockCopy-(LPC0_0+4))
mov r7, sp
movt r1, :upper16:(_OBJC_IVAR_$_ClassA.blockCopy-(LPC0_0+4))
LPC0_0:
add r1, pc
ldr r1, [r1]
add r0, r1
mov r1, r2
blx _objc_storeStrong
pop {r7, pc}
这就是调用objc_storeStrong,它反过来在块上执行retain,在旧块上执行release。我的猜测是 ARC 没有正确注意到它是一个块属性,因为我认为它应该调用 objc_retainBlock 而不是正常的 objc_retain。
或者,我完全错了,实际上 ARC 正在做它记录的事情,而我只是以错误的方式阅读它?
非常欢迎对此进行讨论 - 我觉得这很有趣。
注意事项:
- 它不会在 OS X 上崩溃。
-
O0构建时不会崩溃。
【问题讨论】:
标签: objective-c ios automatic-ref-counting clang