Considere el siguiente código:iOS: Bloque propiedad situada directamente bloquea cuando accede
@interface ClassA : NSObject
@property (nonatomic, copy) void(^blockCopy)();
@end
@implementation ClassA
@synthesize blockCopy;
- (void)giveBlock:(void(^)())inBlock {
blockCopy = inBlock;
}
@end
A continuación, utilizarlo en una clase que tiene un strong
propiedad de tipo ClassA
llamada someA
:
self.someA = [[ClassA alloc] init];
[self.someA giveBlock:^{
NSLog(@"self = %@", self);
}];
dispatch_async(dispatch_get_main_queue(), ^{
self.someA.blockCopy();
self.someA = nil;
});
Si yo ejecutar ese O3
construido con ARC habilitado, en iOS, se bloquea durante la llamada self.someA.blockCopy();
dentro de objc_retain
. ¿Por qué?
Ahora se dan cuenta de que las personas son probablemente va a decir que debería ser la creación con self.blockCopy = inBlock
pero yo tipo de ARC piensan que debería estar haciendo lo correcto. Si miro a la asamblea (ARMv7) producido a partir del método giveBlock:
se ve así:
.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}
que está llamando objc_storeStrong
que a su vez hace un retain
en el bloque y una release
en el viejo bloque. Supongo que ARC no está notando correctamente que es una propiedad de bloque, ya que creo que debería llamar al objc_retainBlock
en lugar del objc_retain
normal.
O, ¿estoy completamente equivocado y en realidad ARC está haciendo lo que documenta y acabo de leerlo de la manera incorrecta?
Discusión muy bienvenida sobre esto - Encuentro esto bastante intrigante.
Puntos a tener en cuenta:
- no choque en OS X.
- No Crash construido
O0
.
Estoy un poco sorprendido de ver que atraviesa un 'objc_storeStrong' cuando asigna, sin embargo, y no puede" hacer lo correcto ". – mattjgalloway
+1 interesante - ty! – Till
Por lo que entiendo (hace un tiempo), existen casos límite que evitan que el compilador emita código que "simplemente funcione" en todos los casos correctamente. Bajo ARC, la línea dura en la arena requiere que el compilador demuestre exactamente que cualquier patrón de código dado siempre funcionará en todas partes. En este caso, no puede hacer eso porque hay usos válidos para argumentos de bloques solo de pila pasados a través de cualquier sitio de llamadas dado (incluyendo 'objc_storeStrong()'). – bbum