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

时间:2013-10-25 00:32:54

标签: ios objective-c nsarray nscoding nssecurecoding

我花了整个下午的时间撞到墙上试图弄清楚为什么这门课的解码失败了。该类有一个属性,它是Foo对象的NSArray。 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

3 个答案:

答案 0 :(得分:5)

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

  

由于未被捕获的异常终止应用&#39; NSInvalidUnarchiveOperationException&#39;,原因:&gt;&#39;关键&#39; NS.objects&#39;是一个意想不到的班级&#39; ClassA&#39;。允许的课程是&#39; {(
  NSArray的
  )}&#39;&#39;

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

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

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

答案 1 :(得分:3)

我刚刚遇到类似的问题,这很奇怪而且非常耗时。我想用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来自我正在开发的开发盒。

答案 2 :(得分:2)

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