Странное поведение при декодировании NSArray через NSSecureCoding

я провел весь день, стуча головой о стену, пытаясь понять, почему декодирование этого класса не работает. у класса есть свойство, которое является NSArray объектов Foo. Foo соответствует NSSecureCoding, и я успешно закодировал и декодировал этот класс сам по себе. я получал сообщение об ошибке в initWithCoder: в нем говорилось, что не удалось декодировать класс Foo. Путем некоторых экспериментов я обнаружил, что мне нужно добавить [класс Foo] в initWithCoder:, чтобы он работал. может быть, это поможет кому-то еще, у кого такая же проблема. у меня вопрос, зачем это нужно? я не нашел никаких указаний на то, что это необходимо в документации Apple.

#import "Foo.h"

@interface MyClass : NSObject <NSSecureCoding>
@property (nonatomic) NSArray *bunchOfFoos;
@end

@implementation MyClass

static NSString *kKeyFoo = @"kKeyFoo";

+ (BOOL) supportsSecureCoding
{
    return YES;
}

- (void) encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:self.bunchOfFoos forKey:kKeyFoo];
}

- (id) initWithCoder:(NSCoder *)decoder
{
    if (self = [super init])
    {
        [Foo class]; // Without this, decoding fails
        _bunchOfFoos = [decoder decodeObjectOfClass:[NSArray class] forKey:kKeyFoo];
    }
    return self;
}

@end

person Ben H    schedule 25.10.2013    source источник
comment
Я думаю, что для того, чего вы пытаетесь достичь, вам нужно реализовать кодирование/декодирование в классе Foo.   -  person zaph    schedule 25.10.2013
comment
да, я сказал, что Foo соответствует NSSecureCoding, что означает, что кодирование/декодирование было реализовано в этом классе.   -  person Ben H    schedule 29.10.2013


Ответы (3)


Для тех, кто все еще борется с этим: решение @Ben H не решило мою проблему. И я продолжаю получать следующее сообщение об ошибке:

Завершение работы приложения из-за необработанного исключения «NSInvalidUnarchiveOperationException», причина: > «значение для ключа «NS.objects» имело непредвиденный класс «ClassA». Допустимые классы: '{(
NSArray
)}'.'.

И, наконец, я понял, что для пользовательских классов. Вместо этого вы должны использовать следующую функцию decodeObjectOfClasses:

- (id)decodeObjectOfClasses:(NSSet *)classes forKey:(NSString *)key

И вы должны передать NSSet всех возможных классов в NSArray функции выше! Я не уверен, почему @Ben H мог решить проблему, просто добавив [Foo class] вне функции. Возможно, это проблема компилятора. Но в любом случае, если его решение не работает, попробуйте и это.

person Yuchen    schedule 30.10.2014
comment
@Gomfucius рад узнать, что это помогает - person Yuchen; 04.02.2016

Я только что столкнулся с подобной проблемой, и это было странно и требовало очень много времени. Я хотел протестировать свой класс на правильность NSSecureCoded с помощью Specta/Expecta. Поэтому я реализовал все по мере необходимости, указав класс при декодировании. В конце моих испытаний я получил самое странное исключение:

value for key 'key' was of unexpected class 'MyClass'. Allowed classes are '{(
    MyClass
)}'.

Тест выглядел примерно так:

MyClass *myClassInstance = ...
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *secureEncoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[secureEncoder setRequiresSecureCoding:YES]; // just to ensure things

NSString *key = @"key";
[secureEncoder encodeObject:myClassInstance forKey:key];
[secureEncoder finishEncoding];

NSKeyedUnarchiver *secureDecoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
[secureDecoder setRequiresSecureCoding:YES];
MyClass *decodedInstance = [secureDecoder decodeObjectOfClass:[MyClass class] forKey:key]; // exception here
[secureDecoder finishDecoding];

...expect...

В то время как простой тест NSCoding (requiresSecureCoding = NO) прошел успешно, тесты NSSecureCoding продолжали давать сбои. После огромного количества испытаний я нашел решение для этого, всего одну строку:

[secureDecoder setClass:[MyClass class] forClassName:NSStringFromClass([MyClass class])];

После этого все мои тесты прошли успешно, объекты создавались как положено.

Я не уверен, почему это произошло, я предполагаю, что класс не виден, как предлагает Ben H, и он использует что-то вроде NSClassFromString(@"MyClass"). Приведенный выше код отлично работал в AppDelegate. MyClass был из модулей разработки, которые я разрабатываю.

person MANIAK_dobrii    schedule 05.03.2015

я думаю, что я, возможно, понял это. без строки [Foo class] в этом файле нет ссылки на класс Foo. из-за этого я считаю, что компилятор оптимизирует класс Foo, и тогда объекты Foo в массиве не могут быть декодированы. наличие [класса Foo] предотвращает это.

person Ben H    schedule 29.10.2013