Почему я не могу закодировать NSValue в NSKeyedArchiver?

Я пытался закодировать 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 ответа

Решение

Согласно документации NSKeyedArchiver учебный класс,

Архив с ключами отличается от архива без ключей тем, что всем объектам и значениям, закодированным в архиве, присваиваются имена или ключи.

Для того, чтобы заархивировать элементы structи дать им ключи NSKeyedArchiver потребуется метаданные, чтобы знать, где каждое поле struct находится, и как называются эти поля. @encode хранится с NSValue дает достаточно информации о макете struct, но информация об именах каждого поля отсутствует.

Поскольку нет метаданных об именах полей в struct, было бы невозможно заархивировать данные таким образом, чтобы обеспечить надлежащее де-архивирование. Поэтому NSKeyedArchiver должен отказаться от архива NSValueсо встроенным C structs.

NSValue используется для инкапсуляции необъектного объекта (например, структур C, целых и т. д.) в объект target-c, но он не обеспечивает способ определения пользовательских процедур архивирования / сериализации для этих упакованных типов. Это просто не является частью его интерфейса.

Если вы хотите заархивировать NSValue, содержащее структуру, вам придется принять во внимание такие вещи, как порядок байтов и обращаться с такими вещами, как вложенные указатели или другие типы, которые не могут быть тривиально записаны как байты. Там нет никакого способа сделать это автоматически с NSValue,

Я столкнулся с той же проблемой и решил, что самым простым решением будет просто скучно и кодировать все значения по отдельности:

- (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];
}
Другие вопросы по тегам