2012-06-06 13 views
7

Considere el siguiente código:Objective-C typedef objeto extraño rendimientos @encode y rompe KVC

#import <Foundation/Foundation.h> 
#import <objc/runtime.h> 

typedef NSString* MyStringRef; 
typedef NSString MyString; 

@interface ClassA : NSObject 
@property (nonatomic, copy) MyStringRef stringA; 
@property (nonatomic, copy) MyString *stringB; 
@end 

@implementation ClassA 
@synthesize stringA = _stringA; 
@synthesize stringB = _stringB; 
@end 

int main() { 
    unsigned int count = 0; 
    Ivar *ivars = class_copyIvarList([ClassA class], &count); 
    for (unsigned int i = 0; i < count; i++) { 
     Ivar thisIvar = ivars[i]; 
     NSLog(@"thisIvar = %s, %s", ivar_getName(thisIvar), ivar_getTypeEncoding(thisIvar)); 
    } 

    ClassA *a = [[ClassA alloc] init]; 
    NSLog(@"Out: %@", [a valueForKey:@"stringA"]); 
    NSLog(@"Out: %@", [a valueForKey:@"stringB"]); 
} 

Ésta es la salida:

$ clang --version 
Apple clang version 3.1 (tags/Apple/clang-318.0.58) (based on LLVM 3.1svn) 
Target: x86_64-apple-darwin11.4.0 
Thread model: posix 

$ clang -o typedef -fobjc-arc -framework Foundation typedef.m && ./typedef 
2012-06-06 20:14:15.881 typedef[37282:707] thisIvar = _stringA, @"NSString" 
2012-06-06 20:14:15.884 typedef[37282:707] thisIvar = _stringB, ^{NSString=#} 
2012-06-06 20:14:15.885 typedef[37282:707] Out: (null) 
2012-06-06 20:14:15.888 typedef[37282:707] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<ClassA 0x7fabe0501480> valueForUndefinedKey:]: this class is not key value coding-compliant for the key stringB.' 
*** First throw call stack: 
(
    0 CoreFoundation      0x00007fff835fef56 __exceptionPreprocess + 198 
    1 libobjc.A.dylib      0x00007fff878e5d5e objc_exception_throw + 43 
    2 CoreFoundation      0x00007fff836891b9 -[NSException raise] + 9 
    3 Foundation       0x00007fff83e77703 -[NSObject(NSKeyValueCoding) valueForUndefinedKey:] + 240 
    4 Foundation       0x00007fff83dae38e _NSGetUsingKeyValueGetter + 108 
    5 Foundation       0x00007fff83dae315 -[NSObject(NSKeyValueCoding) valueForKey:] + 392 
    6 typedef        0x000000010e84bc6d main + 317 
    7 typedef        0x000000010e84b9c4 start + 52 
) 

La pregunta que tengo aquí es lo que se trata Objetivo -C que causa el typedef NSString MyString para crear efectivamente una estructura que contiene una variable del tipo Class y luego usa eso donde yo uso MyString. p.ej. la estructura se parece a esto (después de consultar this):

struct NSString { 
    Class a; 
}; 

De alguna manera tiene sentido, pero hace que el valueForKey: a fallar, presumiblemente debido a que es una estructura ahora, por lo que no puede volver que de la misma manera que los objetos . O más precisamente, cae en la parte de "excepción de lanzamiento" de la orden de búsqueda described in the docs.

Solo me gustaría entender de qué se trata el lenguaje que causa esto y por qué no puede tratar mis 2 tipos de archivos de la misma manera.

+0

Aunque sintetice las propiedades, no parece tener un respaldo real de ellas. –

+4

Las versiones recientes del compilador crean ivars para propiedades sintetizadas automáticamente. –

+0

En general, las cadenas de @encode no son terriblemente útiles. Rápidamente se vuelven excesivamente complejos cuando se trata con tipos de C++, por ejemplo. – bbum

Respuesta

3

Tengo una respuesta a esta en la WWDC 2012. Resulta que se espera que este comportamiento como está para la compatibilidad binaria con GCC.

Me parece extraño que introduzcan de manera efectiva lo que consideraría un error para ser compatible con binarios con los antiguos GCC. Espero que este tipo de cosas eventualmente se elimine a favor de un compilador correcto.

+0

Creo que estoy viendo esto con clang 4.2, FWIW. De acuerdo con el hecho de que se trata de una mala conducta. – nmr

+0

De hecho. Eso es lo que dijo Apple. – mattjgalloway

1

Puedo reproducir esto, pero solo con gcc. Con sonido metálico, me sale:

$ clang --version 
Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn) 
Target: x86_64-apple-darwin10 
Thread model: posix 
$ ./a.out 
2012-06-06 15:16:37.947 a.out[61063:903] thisIvar = _stringA, @"NSString" 
2012-06-06 15:16:37.949 a.out[61063:903] thisIvar = _stringB, @"NSString" 
2012-06-06 15:16:37.949 a.out[61063:903] Out: (null) 
2012-06-06 15:16:37.950 a.out[61063:903] Out: (null) 

Por lo tanto, parece que el sonido metálico desarrolladores están de acuerdo con usted acerca de cómo debería funcionar.

(I también trató de Apple sonido metálico versión 3.0. El mismo buen resultado.)

+0

Interesante, ya que estoy usando clang también. ¿Tiene ARC habilitado en eso? – mattjgalloway

+0

Agregué mi versión de clang y la línea de comando que utilicé para desarrollar mi pregunta. – mattjgalloway

+0

No se usa ARC. 'clang -std = gnu99 foo.m -framework Foundation' Necesitaba gnu99 debido a la declaración de' i' en el bucle 'for'. –