2012-09-05 10 views
6

Non capisco perché sia ​​possibile archiviare le strutture CGPoint ma non le strutture CLLocationCoordinate2D. Qual è la differenza per l'archiviatore?NSKeyedArchiver ha esito negativo con le strutture CLLocationCoordinate2D. Perché?

La piattaforma è iOS. Sono in esecuzione nel simulatore e non ho provato sul 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" ]; 

ottengo un incidente al 2 ° archiveRootObject e questo messaggio viene stampato sulla console:

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

risposta

18

OK, Tom, sei pronto per un po 'di geek? Sono un ragazzo "più vecchio" in questo mondo di giovani whippersnapper. Tuttavia, ricordo alcune cose su C, e sono solo un fanatico del cuore.

Comunque, c'è una sottile differenza tra questo:

typedef struct { double d1, d2; } Foo1; 

e questo:

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

Il primo è un tipo alias a una struttura anonima. Il secondo è un alias di tipo struct Foo2.

Ora, la documentazione per @encode dice che il seguente:

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

si tradurrà in {[email protected]*i} sia per @encode(example) o @encode(Example). Quindi, questo implica che @encode sta usando il tag struct effettivo. Nel caso di un typedef che crea un alias ad una struct anonima, sembra che @encode restituisce sempre ? '

Check this out:

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

In ogni caso, si può indovinare come CLLocationCoordinate2D è definito? Sì. Hai indovinato.

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

Penso che dovresti presentare una segnalazione di bug su questo. O @encode è danneggiato perché non utilizza alias typedefs per le strutture anonime, o CLLocationCoordinate2D deve essere completamente digitato quindi non è una struttura anonima.

+0

Grazie; questa è la spiegazione perfetta! Lo farò riferimento nel mio rapporto radar :) – TomSwift

0

È perché @encode strozzatori su CLLocationCoordinate2D

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

+1

va bene, questo è interessante. così @encode ottiene che è una struttura con due doppi, ma manca il nome del tipo. Come mai? E davvero, perché il nome tipografico è importante per una struttura codificata? – TomSwift

+0

Penso che la codifica generi una stringa usata per fare qualcosa come '[[NSClassFromString (@encode (name)) alloc] init]' o qualche magia nera simile per trovare la funzione che genera 'CLLocationCoord' o' NSPoint' o whatnot . – Clay

3

Per ovviare a questa limitazione finché non viene risolto il bug, è sufficiente abbattere le coordinate e ricostruire:

- (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 }; 
    ...