为什么我不能在NSKeyedArchiver中编码NSValue?

时间:2013-08-28 10:10:51

标签: objective-c cocoa mapkit uikit-state-preservation nsvalue

我试图对MKMapView中心进行编码并跨越NSKeyedArchiver进行状态保存。我找到了几个方便的新MapKit NSValue添加,valueWithMKCoordinate:valueWithMKCoordinate:。试图将这些编码到密钥存档器中失败:

- (void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
    NSValue *mapCenterValue = [NSValue valueWithMKCoordinate:mapView.centerCoordinate];
    NSValue *mapSpanValue = [NSValue valueWithMKCoordinateSpan:mapView.region.span];
    [coder encodeObject:mapCenterValue forKey:kMapCenter];
    [coder encodeObject:mapSpanValue forKey:kMapSpan];
}
  

由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:' - [NSKeyedArchiver encodeValueOfObjCType:at:]:此归档程序无法编码结构'

我理解这个问题的解决方案是将单个双打编码为四个单独的密钥。

我的问题是为什么会发生这种情况。 NSValue是一个对象,为什么它告诉我“这个归档器不能编码结构”

3 个答案:

答案 0 :(得分:4)

根据NSKeyedArchiver类的文档,

  

密钥存档与非密钥存档的不同之处在于,编码到存档中的所有对象和值都是名称或密钥。

为了归档struct的元素并为其提供密钥NSKeyedArchiver,需要元数据来了解struct的每个字段的位置,以及这些字符的名称是什么领域。与@encode一起存储的NSValue为其提供了有关struct布局的足够信息,但缺少有关每个字段名称的信息。

由于struct中没有关于字段名称的元数据,因此无法以确保正确取消存档的方式存档数据。这就是为什么NSKeyedArchiver必须拒绝存档嵌入了C NSValue的{​​{1}}。

答案 1 :(得分:2)

我遇到了同样的问题,并认为最简单的解决方案就是无聊并单独编码所有值:

- (void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
    MKCoordinateRegion region = [self.mapView region];
    [coder encodeDouble:region.center.latitude forKey:RWSMapCenterLatitude];
    [coder encodeDouble:region.center.longitude forKey:RWSMapCenterLongitude];
    [coder encodeDouble:region.span.latitudeDelta forKey:RWSMapCenterLatitudeDelta];
    [coder encodeDouble:region.span.longitudeDelta forKey:RWSMapCenterLongitudeDelta];

    [super encodeRestorableStateWithCoder:coder];
}

- (void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
    MKCoordinateRegion region;
    CLLocationCoordinate2D center;
    center.latitude = [coder decodeDoubleForKey:RWSMapCenterLatitude];
    center.longitude = [coder decodeDoubleForKey:RWSMapCenterLongitude];
    region.center = center;
    MKCoordinateSpan span;
    span.latitudeDelta = [coder decodeDoubleForKey:RWSMapCenterLatitudeDelta];
    span.longitudeDelta = [coder decodeDoubleForKey:RWSMapCenterLongitudeDelta];
    region.span = span;

    self.mapView.region = region;

    [super decodeRestorableStateWithCoder:coder];
}

答案 2 :(得分:1)

NSValue用于将非对象(例如C结构,整数等)封装到objective-c对象中,但它没有提供为这些包装定义自定义归档/序列化例程的方法类型。这只是其界面的一部分。

如果你想归档一个包含结构的NSValue,你必须考虑像endianness这样的东西,并处理嵌套指针或其他类型的东西,这些类型不能简单地写成字节。使用NSValue无法自动执行此操作。