通过NSSecureCoding解码NSArray时的奇怪行为

我花了整个下午的时间撞到墙上试图弄清楚为什么这门课的解码失败了。 该类有一个属性,它是Foo对象的NSArray。 Foo符合NSSecureCoding,我已经成功编码并解码了该类。 我在initWithCoder中遇到错误:表示无法解码类Foo。 通过一些实验,我发现我需要将[Foo类]添加到initWithCoder:为了使它工作。 也许这会帮助那些遇到同样问题的人。 我的问题是,为什么这是必要的? 我没有发现在Apple的文档中这是必要的。

#import "Foo.h" @interface MyClass : NSObject  @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 

我刚刚遇到类似的问题,这很奇怪而且非常耗时。 我想用Specta / Expecta测试我的类是否正确NSSecureCoded 。 所以我已经根据需要实现了一切,在解码时指定了类。 在我的审判结束时,我得到了最奇怪的例外:

 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来自我正在开发的开发盒。

对于那些仍在努力解决这个问题的人:@Ben H的解决方案并没有解决我的问题。 我一直有以下错误消息:

由于未捕获的exception’NSInvalidUnarchiveOperationException’终止应用程序,原因:>’key’NS.objects’的值是意外的类’ClassA’。 允许的class级是'{(
NSArray的
)} ”

最后,我意识到自定义类。 您必须使用以下函数而不是decodeObjectOfClasses

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

并且您将NSArray中所有可能类的NSSet传递给上面的函数! 我不确定为什么@Ben H可以通过简单地在函数外添加[Foo class]来解决问题。 也许这是编译器问题。 但无论如何,如果他的解决方案不起作用,也可以尝试这个。

我想我可能已经弄明白了。 没有行[Foo class],这个文件中没有类Foo的引用。 因此,我相信编译器正在优化Foo类,然后无法解码数组中的Foo对象。 在那里有[Foo类]可以防止这种情况发生。