2012-05-28 11 views
13

Così, sono stato nei guai con l'objc-runtime di nuovo (sorpresa sorpresa), e ho trovato un blocco di codice interessante here:Perché non possiamo usare le stringhe C come SEL?

const char *sel_getName(SEL sel) { 
#if SUPPORT_IGNORED_SELECTOR_CONSTANT 
    if ((uintptr_t)sel == kIgnore) return "<ignored selector>"; 
#endif 
    return sel ? (const char *)sel : "<null selector>"; 
} 

Allora, che cosa questo mi dice è che un SEL è equivalente a una corda a C, in ogni manierismo. Facendo un esadecimale dei primi 16 byte di SEL che contiene @selector(addObject:) dà la seguente:

61 64 64 4F 62 6A 65 63 74 3A 00 00 00 00 00 00

che è uguale a la stringa C addObject:.

Detto questo, perché questo codice si arresta in modo anomalo quando utilizzo la stringa C come selettore?

SEL normalSEL = @selector(addObject:); 
SEL cStringSEL = (SEL) "addObject:"; 

NSMutableArray *arr = [NSMutableArray arrayWithObjects:@"1", @"2", nil]; 

[arr performSelector:normalSEL withObject:@"3"]; 
[arr performSelector:cStringSEL withObject:@"4"]; 

NSLog(@"%@", arr); 

Per quanto posso dire, il contenuto dei selettori sono gli stessi, quindi perché l'incidente sul secondo con il seguente messaggio di errore?

*** terminazione app a causa di eccezione non identificata 'NSInvalidArgumentException', motivo: '- [__ NSArrayM addObject:]: selettore non riconosciuto inviato ad esempio 0x101918720' ***

+3

Si noti che è possibile utilizzare 'sel_registerName()' per trasformare una stringa C in una SEL benedetta (in pratica, unifica la stringa dietro le quinte per conservare l'identità del puntatore successiva). Nota anche che non dovresti mai fare affidamento direttamente su un SEL come un 'char *'. Probabilmente lo sarà sempre, ma ciò non rende corretta l'ipotesi. – bbum

risposta

22

selettori sono internati stringhe C e sono confrontato dal loro indirizzo, non dal loro contenuto. Il contenuto delle stringhe viene utilizzato solo per la conversione in/da una rappresentazione di stringa esterna. Interning è fatto per migliorare le prestazioni - quando il runtime sta cercando l'implementazione del metodo che corrisponde a un selettore, può confrontare direttamente i puntatori selettori invece di dereferenziare ciascun puntatore e confrontare i caratteri.

+0

Hmm ... dopo aver esaminato '__sel_registerName', credo che tu abbia ragione. Tuttavia, mi chiedo quanta differenza di prestazioni ci sarebbe davvero ... –

+0

Questo è anche fortemente implicito dalla stringa/selettore API; vedere i documenti per ['NSSelectorFromString()'] (https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/doc/ uid/20000055-BCIEICGB) e la sua connessione a 'sel_registerName()'. –

+13

objc_msgSend viene eseguito in circa 8 cicli in questi giorni. Non c'è molto spazio per uno strcmp() in là;) –