2012-09-05 9 views
6

Nie rozumiem, dlaczego mogę zarchiwizować struktury CGPoint, ale nie można ich użyć w postaci CLLocationCoordinate2D. Czym się różni archiwizer?NSKeyedArchiver kończy się niepowodzeniem ze strukturami CLLocationCoordinate2D. Czemu?

Platforma to iOS. Biegnę w symulatorze i nie próbowałem na urządzeniu.

// 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" ]; 

mam awarię na 2 archiveRootObject a ten komunikat zostanie wydrukowany do konsoli:

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

Odpowiedz

18

OK, Tom, jesteś gotowy na trochę geek? Jestem "starszym" facetem w tym świecie młodych whippersnaperów. Jednak pamiętam kilka rzeczy o C i jestem po prostu geekem w sercu.

W każdym razie, istnieje subtelne różnice między tym:

typedef struct { double d1, d2; } Foo1; 

a to:

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

Pierwszy jest typu alias anonimowego struktury. Drugi to alias typu do struct Foo2.

Teraz dokumentacja @encode mówi, że:

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

spowoduje {[email protected]*i} zarówno @encode(example) lub @encode(Example). Oznacza to, że @encode używa rzeczywistego znacznika struct. W przypadku typedef, który tworzy alias do anonimowej struktury, wygląda @encode zawsze zwraca ? '

to sprawdzić:

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

W każdym razie, można się domyślać, jak CLLocationCoordinate2D jest zdefiniowana? Tak. Zgadłeś.

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

Myślę, że powinieneś złożyć zgłoszenie błędu na ten temat. Albo @encode jest zepsuty, ponieważ nie używa aliasu typedefs do anonimowych struktur, albo CLLocationCoordinate2D musi być w pełni wpisany, więc nie jest anonimową strukturą.

+0

Dzięki; to doskonałe wyjaśnienie! Powołam to w moim raporcie radarowym :) – TomSwift

0

To dlatego @encode dławiki na CLLocationCoordinate2D

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

+1

w porządku, to jest interesujące. więc @encode pobiera, że ​​jest to struktura z dwoma podwójnymi, ale pomija nazwę typu. Dlaczego? I naprawdę, dlaczego nazwa pliku ma znaczenie dla zakodowanej struktury? – TomSwift

+0

Myślę, że kodowanie generuje ciąg, który jest używany do zrobienia czegoś takiego jak: [[NSClassFromString (@ kodode (name)) alloc] init] 'lub jakaś podobna czarna magia, aby znaleźć funkcję, która generuje' CLLocationCoord' lub 'NSPoint' lub inne . – Clay

3

Aby obejść to ograniczenie, aż problem został rozwiązany, po prostu rozbić współrzędne i zrekonstruować:

- (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 }; 
    ... 
Powiązane problemy