2012-05-28 10 views
13

lo tanto, he estado jugando con el objc-tiempo de ejecución de nuevo (oh sorpresa), y me encontré con un bloque interesante de código here:¿Por qué no podemos usar C-strings como 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>"; 
} 

lo tanto, lo que esto me dice es que un SEL es equivalente a una C-cadena, en cada manierismo. Hacer un volcado hexadecimal de los primeros 16 bytes de SEL que contiene @selector(addObject:) da la siguiente:

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

que es igual a la C-cadena addObject:.

Dicho esto, ¿por qué este código se bloquea cuando uso la C-string como selector?

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); 

Por lo que yo puedo decir, el contenido de los selectores son los mismos, ¿por qué el accidente en la segunda con el siguiente mensaje de error?

*** Terminación de aplicación debido a excepción no detectada 'NSInvalidArgumentException', razón: '- [__ NSArrayM addObject:]: Selector no reconocido enviado a la instancia 0x101918720' ***

+3

Tenga en cuenta que puede usar 'sel_registerName()' para convertir una cadena C en un bendito SEL (Básicamente, única la cadena detrás de las escenas para preservar la identidad del puntero posterior). Tenga en cuenta también que nunca debe confiar directamente en que un SEL sea un 'char *'. Probablemente siempre lo será, pero eso no hace que la suposición sea correcta. – bbum

Respuesta

22

selectores están internados cadenas de C y son comparado por su dirección, no su contenido. El contenido de la cadena solo se usa para convertir a/desde una representación de cadena externa. La internación se hace para mejorar el rendimiento: cuando el motor de ejecución busca la implementación del método que coincida con un selector, puede comparar los punteros del selector directamente en lugar de desreferenciar cada puntero y comparar los caracteres.

+0

Hmm ... después de investigar '__sel_registerName', creo que estás en lo cierto. Aún así, me pregunto cuánto de una diferencia de rendimiento realmente sería ... –

+0

Esto también está fuertemente implícito en la API string/selector; vea los documentos para ['NSSelectorFromString()'] (https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/doc/ uid/20000055-BCIEICGB) y su conexión a 'sel_registerName()'. –

+13

objc_msgSend se ejecuta en alrededor de 8 ciclos en estos días. No hay mucho espacio para un strcmp() allí;) –

Cuestiones relacionadas