NSKeyedArchiver失败并显示CLLocationCoordinate2D结构。为什么?

问题描述:

我不明白我为什么可以存档CGPoint结构但不是CLLocationCoordinate2D结构。归档人员有什么不同?NSKeyedArchiver失败并显示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" ]; 

我得到二号archiveRootObject崩溃,并且该消息被打印到控制台:

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

OK,汤姆,你准备好了一些极客?我是这个年轻鞭挞者世界中的“年长”的家伙。不过,我记得关于C的一些事情,而我只是一个极客。

无论如何,有这之间的细微差别:

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; 

将导致{[email protected]*i}两个@encode(example)@encode(Example)。所以,这意味着@encode正在使用实际的结构标记。在创建别名匿名结构的类型定义的情况下,它看起来像@encode总是返回?

检查了这一点:

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

无论如何,你可以猜测CLLocationCoordinate2D是如何定义的?是的。你猜到了。

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

我想你应该就此提交一份错误报告。 @encode因为它不使用匿名类型定义到匿名结构而被破坏,或者CLLocationCoordinate2D需要被完全键入,因此它不是匿名结构。

+0

谢谢;这是完美的解释!我会在我的雷达报告中引用它:) – TomSwift

这是因为@encode扼流圈CLLocationCoordinate2D

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

+1

好,这很有趣。所以@encode得到它是一个有两个双打但没有输入类型名称的结构。怎么来的?实际上,为什么typename对于编码结构很重要? – TomSwift

+0

我认为这个编码生成一个字符串,用来做''[NSClassFromString(@encode(name))alloc] init]'或者类似的黑魔法来找到产生'CLLocationCoord'或'NSPoint'或者什么的函数。 – Clay

要解决这个限制,直到错误是固定的,简单地分解坐标和重建:

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