Сбой 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}