Рассмотрим следующий код:
@interface ClassA : NSObject
@property (nonatomic, copy) void(^blockCopy)();
@end
@implementation ClassA
@synthesize blockCopy;
- (void)giveBlock:(void(^)())inBlock {
blockCopy = inBlock;
}
@end
Затем используйте его в классе, который имеет свойство strong
типа ClassA
с именем someA
:
self.someA = [[ClassA alloc] init];
[self.someA giveBlock:^{
NSLog(@"self = %@", self);
}];
dispatch_async(dispatch_get_main_queue(), ^{
self.someA.blockCopy();
self.someA = nil;
});
ЕслиЯ запускаю тот встроенный O3
с включенным ARC, на iOS он вылетает во время вызова self.someA.blockCopy();
внутри objc_retain
.Почему?
Теперь я понимаю, что люди, вероятно, скажут, что я должен установить это с self.blockCopy = inBlock
, но я действительно думал, что ARC должна делать правильные вещи здесь.Если я посмотрю на сборку (ARMv7), созданную методом giveBlock:
, то она будет выглядеть следующим образом:
.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
.