2012-09-05 15 views
6

No entiendo por qué puedo archivar las estructuras de CGPoint pero no CLLocationCoordinate2D structs. ¿Cuál es la diferencia para el archivador?NSKeyedArchiver falla con CLLocationCoordinate2D structs. ¿Por qué?

La plataforma es iOS. Estoy corriendo en el simulador y no lo he probado en el dispositivo.

// why does this work: 
NSMutableArray *points = [[[NSMutableArray alloc] init] autorelease]; 
CGPoint p = CGPointMake(10, 11); 
[points addObject:[NSValue valueWithBytes: &p objCType: @encode(CGPoint)]]; 
[NSKeyedArchiver archiveRootObject:points toFile: @"/Volumes/Macintosh HD 2/points.bin" ]; 

// and this doesnt work: 
NSMutableArray *coords = [[[NSMutableArray alloc] init] autorelease]; 
CLLocationCoordinate2D c = CLLocationCoordinate2DMake(121, 41); 
[coords addObject:[NSValue valueWithBytes: &c objCType: @encode(CLLocationCoordinate2D)]]; 
[NSKeyedArchiver archiveRootObject:coords toFile: @"/Volumes/Macintosh HD 2/coords.bin" ]; 

me sale un accidente en la segunda archiveRootObject y este mensaje se imprime en la consola:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSKeyedArchiver encodeValueOfObjCType:at:]: this archiver cannot encode structs' 

Respuesta

18

OK, Tom, ¿estás listo para un poco de friki? Soy un chico "mayor" en este mundo de jóvenes traficantes. Sin embargo, recuerdo algunas cosas sobre C, y solo soy un friki de corazón.

De todos modos, hay una sutil diferencia entre este:

typedef struct { double d1, d2; } Foo1; 

y esto:

typedef struct Foo2 { double d1, d2; } Foo2; 

El primero es un tipo de alias a una estructura anónima. El segundo es un alias tipo al struct Foo2.

Ahora, la documentación para @encode dice que la siguiente:

typedef struct example { 
    id anObject; 
    char *aString; 
    int anInt; 
} Example; 

dará lugar a {[email protected]*i} tanto para @encode(example) o @encode(Example). Entonces, esto implica que @encode está usando la etiqueta struct real. En el caso de un typedef que crea un alias a una estructura anónima, parece que siempre devuelve @encode? '

mira esto:

NSLog(@"Foo1: %s", @encode(Foo1)); 
NSLog(@"Foo2: %s", @encode(Foo2)); 

De todos modos, se puede adivinar cómo se define CLLocationCoordinate2D? Sí. Lo adivinaste.

typedef struct { 
CLLocationDegrees latitude; 
CLLocationDegrees longitude; 
} CLLocationCoordinate2D; 

Creo que debe presentar un informe de error al respecto. O bien @encode está roto porque no usa alias typedefs en estructuras anónimas, o CLLocationCoordinate2D necesita estar totalmente tipado para que no sea una estructura anónima.

+0

Gracias; esa es la explicación perfecta! Lo haré referencia en mi informe de radar :) – TomSwift

0

Es porque @encode ahoga en CLLocationCoordinate2D

NSLog(@"coords %@; type: %s", coords, @encode(CLLocationCoordinate2D)); rendimientos coords ( "<00000000 00405e40 00000000 00804440>" ); type: {?=dd}

+1

bien, eso es interesante. así que @encode entiende que es una estructura con dos dobles, pero pierde el nombre del tipo. ¿Cómo? Y realmente, ¿por qué importa typename para una estructura codificada? – TomSwift

+0

Creo que la codificación genera una cadena que se utiliza para hacer algo como '[[NSClassFromString (@encode (name)) alloc] init]' o alguna magia negra similar para encontrar la función que genera 'CLLocationCoord' o' NSPoint' o lo que sea . – Clay

3

Para superar esta limitación hasta que se corrija el error, basta con romper las coordenadas y reconstruir:

- (void)encodeWithCoder:(NSCoder *)coder 
{ 
    NSNumber *latitude = [NSNumber numberWithDouble:self.coordinate.latitude]; 
    NSNumber *longitude = [NSNumber numberWithDouble:self.coordinate.longitude]; 
    [coder encodeObject:latitude forKey:@"latitude"]; 
    [coder encodeObject:longitude forKey:@"longitude"]; 
    ... 

- (id)initWithCoder:(NSCoder *)decoder 
{ 
    CLLocationDegrees latitude = (CLLocationDegrees)[(NSNumber*)[decoder decodeObjectForKey:@"latitude"] doubleValue]; 
    CLLocationDegrees longitude = (CLLocationDegrees)[(NSNumber*)[decoder decodeObjectForKey:@"longitude"] doubleValue]; 
    CLLocationCoordinate2D coordinate = (CLLocationCoordinate2D) { latitude, longitude }; 
    ... 
Cuestiones relacionadas