【问题标题】: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'

【问题讨论】:

    标签: objective-c ios nskeyedarchiver


    【解决方案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 或诸如此类的函数。
      猜你喜欢
      • 1970-01-01
      • 2012-04-06
      • 1970-01-01
      • 2012-09-08
      • 2013-09-24
      • 2011-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多