NSKeyedArchiver 因 CLLocationCoordinate2D 结构而失败。为啥?
Posted
技术标签:
【中文标题】NSKeyedArchiver 因 CLLocationCoordinate2D 结构而失败。为啥?【英文标题】:NSKeyedArchiver fails with CLLocationCoordinate2D structs. Why?NSKeyedArchiver 因 CLLocationCoordinate2D 结构而失败。为什么? 【发布时间】:2012-08-30 18:05:31 【问题描述】:我不明白为什么我可以存档 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'
【问题讨论】:
【参考方案1】:要在错误修复之前绕过此限制,只需分解坐标并重建即可:
- (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 ;
...
【讨论】:
【参考方案2】:好的,汤姆,你准备好迎接极客了吗?在这个年轻的whippersnappers世界里,我是一个“老”的人。但是,我记得一些关于 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;
对于@encode(example)
或@encode(Example)
将产生example=@*i
。因此,这意味着 @encode
正在使用实际的结构标记。对于为匿名结构创建别名的 typedef,看起来 @encode
总是返回 ?
'
看看这个:
NSLog(@"Foo1: %s", @encode(Foo1));
NSLog(@"Foo2: %s", @encode(Foo2));
不管怎样,你能猜出 CLLocationCoordinate2D 是如何定义的吗?是的。你猜对了。
typedef struct
CLLocationDegrees latitude;
CLLocationDegrees longitude;
CLLocationCoordinate2D;
我认为您应该就此提交错误报告。要么@encode
被破坏,因为它没有对匿名结构使用别名类型定义,要么 CLLocationCoordinate2D 需要完全类型化,因此它不是匿名结构。
【讨论】:
谢谢;这就是完美的解释!我会在我的雷达报告中引用它:) 现在定义为:struct CLLocationCoordinate2D CLLocationDegrees latitude; CLLocationDegrees 经度; ; typedef struct CLLocationCoordinate2D CLLocationCoordinate2D;所以我猜@encode 坏了。【参考方案3】:这是因为@encode
阻塞了 CLLocationCoordinate2D
NSLog(@"coords %@; type: %s", coords, @encode(CLLocationCoordinate2D));
产生coords (
"<00000000 00405e40 00000000 00804440>"
); type: ?=dd
【讨论】:
好的,这很有趣。所以@encode 得到它是一个有两个双精度的结构,但错过了类型名称。怎么会?真的,为什么类型名对编码结构很重要? 我认为编码会生成一个字符串,该字符串用于执行[[NSClassFromString(@encode(name)) alloc] init]
之类的操作或一些类似的黑魔法,以找到生成CLLocationCoord
或NSPoint
或诸如此类的函数。以上是关于NSKeyedArchiver 因 CLLocationCoordinate2D 结构而失败。为啥?的主要内容,如果未能解决你的问题,请参考以下文章
从 NSKeyedArchiver 中提取 NSString
如何将 UIDocumentPickerViewController 导入限制为 .archive 文件? (NSKeyedArchiver)