NSSecureCoding возвращает ноль для правильно сохраненного объекта

у меня macOS 10.15 (bigSUr), XCode 12, target-c, а не ios.

У меня есть приложение на основе документов. Он имеет простой объект SHGlobalAppData (NSObject), который содержит объект свойств пользовательского класса SHSetupDataModel (NSObject).

При загрузке initWithCoder возвращает nil для сохраненного значения. Почему?

Это реализация:

Я использую NSSecureCoding, поэтому и SHSetupDataModel, и SHGlobalAppData включают соответствующий метод класса.

+ (BOOL)supportsSecureCoding { return YES;}

Сохранение выполняется в NSDocument с безопасным кодированием

- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError {
    
    NSKeyedArchiver* archiver=[[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
    [archiver encodeObject:self.appData forKey:@"appData"]; // SHSetupDataModel is a property of appData object
    //[...]
}

Как происходит экономия

Когда дело доходит до сохранения, это код для SHGlobalAppData.

- (void)encodeWithCoder:(NSCoder *)coder {

    // Other properties here

    if (_setupData){
        // Tests
        NSLog(@"%@",[_setupData className]); // returns "SHSetupDataModel"
        BOOL test = [_setupData isKindOfClass:[SHSetupDataModel class]]; // returns TRUE

        [coder encodeObject:_setupData forKey:@"setupData"];
    }
}

Вышеуказанная экономия проходит гладко. Тесты в порядке.

Как происходит загрузка

Теперь при загрузке сохраненного файла вызывается следующий метод NSDocument:

- (BOOL)readFromURL:(NSURL *)url ofType:(NSString *)typeName error:(NSError *__autoreleasing  _Nullable *)outError {

    NSData* data = [[NSData alloc] initWithContentsOfURL:url];
    NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:outError];
    [unarchiver setRequiresSecureCoding:YES];

    // Load appData
    SHGlobalAppData* appData = [unarchiver decodeObjectOfClass:[SHGlobalAppData class] forKey:@"appData"];
    [unarchiver finishDecoding];
    // [...]
}

Это вызывает форму метода initWithCoder SHGlobalAppData, где я получаю нулевой результат

- (id)initWithCoder:(NSCoder *)coder {

    self = [super initWithCoder:coder];
    
    if (self) {
        
        if ([coder containsValueForKey:@"setupData"]){
            _setupData = [coder decodeObjectOfClass:[SHSetupDataModel class] forKey:@"setupData"];   // <---- This is nil. Why?              
        }
        // [...]
    }
}

Может ли кто-нибудь помочь мне, почему это возвращает ноль? Или привести меня к более эффективной отладке?


person Pat_Morita    schedule 03.04.2021    source источник


Ответы (1)


Сама модель данных содержала NSDictionary, который не был должным образом декодирован. Решение состояло в том, чтобы проанализировать outError, а затем пошагово проработать методы initWithCoder. Наконец, мне пришлось передать несколько классов в decodeObjectWithClasses:ofKey:

person Pat_Morita    schedule 05.04.2021