Ecco l'effettiva attuazione del retain
da tardi nel file:
__attribute__((aligned(16)))
id
objc_retain(id obj)
{
if (!obj || OBJC_IS_TAGGED_PTR(obj)) {
goto out_slow;
}
#if __OBJC2__
if (((class_t *)obj->isa)->hasCustomRR()) {
return [obj retain];
}
return bypass_msgSend_retain(obj);
#else
return [obj retain];
#endif
out_slow:
// clang really wants to reorder the "mov %rdi, %rax" early
// force better code gen with a data barrier
asm volatile("");
return obj;
}
Quindi, se si tratta di un puntatore con tag, non fare nulla. Abbastanza corretto, ciò significa che in realtà non si riferisce a nulla sullo heap e non vi è alcun numero di ritenzione.
Altrimenti, ai vecchi tempi, avevano appena inviato il messaggio retain
all'oggetto. Ora inviano il messaggio retain
all'oggetto se è stato annotato che contiene un numero personalizzato retain
(senza dubbio non qualcosa che il vecchio runtime registra, quindi il controllo della versione) altrimenti utilizza il metodo bypass.
Il bypass sembra chiamare direttamente l'indirizzo noto di [NSObject retain]
.
Quindi la mia ipotesi? È un'ottimizzazione della velocità. Se è possibile affermare che non è disponibile la conservazione personalizzata e che, in effetti, passa direttamente a IMP
, si risparmia il costo della spedizione dinamica. Dato che il compilatore ora lancia le chiamate C automaticamente sotto ARC (in particolare non le chiamate Objective-C), significa che non si entra mai nelle cose più costose.
Quelle sembrano invocazioni esplicite di conservazione, rilascio e autorelease, per aggirare il desiderio del compilatore di opporsi allo stesso. Per quanto riguarda il motivo per cui sono presenti, non ne ho idea. –
In che file si trova? –
http://opensource.apple.com/source/objc4/objc4-532.2/runtime/NSObject.mm –