Сбой NSKeyedArchiver со структурами CLLocationCoordinate2D. Зачем?

Я не понимаю, почему я могу архивировать CGPoint структурирует но не CLLocationCoordinate2D Структуры. Какая разница с архиватором?

Платформа iOS. Я бегу в симуляторе и еще не пробовал на устройстве.

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

Я получаю сбой на 2-й archiveRootObject и это сообщение выводится на консоль:

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

3 ответа

Решение

Хорошо, Том, ты готов к чему-то ненормальному? Я "пожилой" парень в этом мире юных болотников. Тем не менее, я помню несколько вещей о Си, и я просто фанатик в душе.

В любом случае, между этим есть небольшая разница:

typedef struct { double d1, d2; } Foo1;

и это:

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

Первый - псевдоним типа для анонимной структуры. Второй тип псевдоним для struct Foo2,

Теперь документация для @encode говорит что следующее:

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

приведет к {example=@*i} для обоих @encode(example) или же @encode(Example), Итак, это означает, что @encode использует фактический тег структуры. В случае с typedef, который создает псевдоним для анонимной структуры, он выглядит так: @encode всегда возвращается ?'

Проверь это:

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

В любом случае, вы можете догадаться, как определяется CLLocationCoordinate2D? Ага. Ты угадал.

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

Я думаю, что вы должны подать отчет об ошибке по этому вопросу. Или @encode сломан, потому что он не использует псевдонимы typedefs для анонимных структур, или CLLocationCoordinate2D должен быть полностью типизирован, чтобы он не был анонимной структурой.

Чтобы обойти это ограничение, пока ошибка не будет устранена, просто разбейте координаты и восстановите:

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

Это потому что @encode дросселирует CLLocationCoordinate2D

NSLog(@"coords %@; type: %s", coords, @encode(CLLocationCoordinate2D)); доходность coords ( "<00000000 00405e40 00000000 00804440>" ); type: {?=dd}

Другие вопросы по тегам