Si consideri il seguente codice:iOS: Block proprietà ubicata direttamente si blocca quando accede
@interface ClassA : NSObject
@property (nonatomic, copy) void(^blockCopy)();
@end
@implementation ClassA
@synthesize blockCopy;
- (void)giveBlock:(void(^)())inBlock {
blockCopy = inBlock;
}
@end
Quindi utilizzare in una classe che ha una proprietà strong
di tipo ClassA
chiamato someA
:
self.someA = [[ClassA alloc] init];
[self.someA giveBlock:^{
NSLog(@"self = %@", self);
}];
dispatch_async(dispatch_get_main_queue(), ^{
self.someA.blockCopy();
self.someA = nil;
});
Se io eseguire quello costruito O3
con ARC abilitato, su iOS, si blocca durante la chiamata self.someA.blockCopy();
all'interno di objc_retain
. Perché?
Ora mi rendo conto che probabilmente le persone diranno che dovrei impostarlo con self.blockCopy = inBlock
ma ho pensato che ARC avrebbe dovuto fare la cosa giusta qui. Se guardo l'assemblea (ARMv7) prodotta dal metodo giveBlock:
sembra che questo:
.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}
che chiama objc_storeStrong
che a sua volta fa un retain
sul blocco e un release
sul vecchio blocco. La mia ipotesi è che ARC non sta notando correttamente che si tratta di una proprietà di blocco, perché penso che dovrebbe chiamare objc_retainBlock
anziché il normale objc_retain
.
Oppure, sono semplicemente totalmente in errore e in realtà ARC sta facendo quello che documenta e l'ho appena letto nel modo sbagliato?
Discussione molto benvenuta su questo - Trovo che questo sia piuttosto intrigante.
Punti da notare:
- Esso non va in crash su OS X.
- Non va in crash costruito
O0
.
Sono solo un po 'sorpreso nel vederlo passare attraverso un 'objc_storeStrong' quando lo assegno, e non essere in grado di" fare la cosa giusta ". – mattjgalloway
+1 interessante - ty! – Till
Da quello che ho capito (stato un po '), ci sono casi limite che impediscono al compilatore di emettere codice che "funziona" in tutti i casi correttamente. Sotto ARC, la linea dura nella sabbia richiede al compilatore di essere in grado di dimostrare esattamente che ogni modello di codice dato funzionerà sempre tutto il tempo. In questo caso, non può farlo perché ci sono usi validi per gli argomenti di blocco solo stack passati attraverso qualsiasi sito di chiamata dato (incluso 'objc_storeStrong()'). – bbum