15

我在采用 NSSecureCoding 时遇到了麻烦。我对包含我的自定义类的对象的数组进行编码,该类NSSecureCoding正确采用。当我解码它并传递类NSArray(这是我编码的对象的类)时,它会引发异常。但是,当对字符串数组执行完全相同的操作时,它可以正常工作。我看不出我的班级和 NSString 有什么区别。

#import <Foundation/Foundation.h>

@interface Foo : NSObject <NSSecureCoding>
@end
@implementation Foo
- (id)initWithCoder:(NSCoder *)aDecoder {
  return [super init];
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
}
+ (BOOL)supportsSecureCoding {
  return YES;
}
@end

int main() {
  @autoreleasepool {

    NSMutableData* data = [[NSMutableData alloc] init];
    NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    [archiver encodeObject:@[[Foo new]] forKey:@"foo"];
    [archiver encodeObject:@[@"bar"] forKey:@"bar"];
    [archiver finishEncoding];

    NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    unarchiver.requiresSecureCoding = YES;
    // throws exception: 'value for key 'NS.objects' was of unexpected class 'Foo'. Allowed classes are '{( NSArray )}'.'
    [unarchiver decodeObjectOfClass:[NSArray class] forKey:@"foo"];
    // but this line works fine:
    [unarchiver decodeObjectOfClass:[NSArray class] forKey:@"bar"];
    [unarchiver finishDecoding];

  }
  return 0;
}
4

3 回答 3

17

你可能已经解决了这个问题,但我只是点击了这个并找到了一个解决方案,并认为我会把它留在这里,让其他找到这个的人。

我的解决方案是使用decodeObjectOfClasses:forKey:

迅速:

    if let data = defaults.objectForKey(FinderSyncKey) as? NSData
        let unArchiver = NSKeyedUnarchiver(forReadingWithData: data)
        unArchiver.setRequiresSecureCoding(true)
         //This line is most likely not needed, I was decoding the same object across modules
        unArchiver.setClass(CustomClass.classForCoder(), forClassName: "parentModule.CustomClass")
        let allowedClasses = NSSet(objects: NSArray.classForCoder(),CustomClass.classForCoder())
        if let unarchived = unArchiver.decodeObjectOfClasses(allowedClasses, forKey:NSKeyedArchiveRootObjectKey) as?  [CustomClass]{
            return unarchived

        }    
    }

在objective-C中它会是这样的[unArchiver decodeObjectOfClasses:allowedClasses forKey:NSKeyedArchiveRootObjectKey]

将解码对象更改为解码对象为我解决了上述异常。

于 2014-11-10T03:13:43.253 回答
8

在 Swift 5 中,我真的为此苦苦挣扎了一个小时。

我的情况是我有一组自定义解决方案对象:

var resultsSet = Set<Solution>()

符合安全编码:

static var supportsSecureCoding: Bool{ get{ return true } }

由于安全编码,它们的容器对象将它们编码为 NSSet:

aCoder.encode(resultsSet as NSSet, forKey: "resultsSet")

但是我在解码过程中总是遇到编译器错误:

if let decodedResultsSet = aDecoder.decodeObject(of: NSSet.self, forKey: "resultsSet"){

            resultsSet = decodedResultsSet as! Set<Solution>
        }

错误:

2020-02-11 22:35:06.555015+1300 恢复键“NS.objects”的状态值属于意外类“App.Solution”时发生异常。允许的类是'{( NSSet )}'。2020-02-11 22:35:06.564758+1300 *** 由于未捕获的异常“NSInvalidUnarchiveOperationException”而终止应用程序,原因:“键“NS.objects”的值属于意外类“App.Solution”。允许的类是'{( NSSet )}'。

如果我将 decodeObject(ofClass: 更改为解决方案:

if let decodedResultsSet = aDecoder.decodeObject(of: Solution.self, forKey: "resultsSet"){

            resultsSet = decodedResultsSet as! Set<Solution>
        }

我得到错误:

2020-02-11 22:33:46.924580+1300 恢复键“resultsSet”的状态值属于意外类“NSSet”时发生异常。允许的类是“{(app.Solution)}”。2020-02-11 22:33:46.933812+1300 *** 由于未捕获的异常“NSInvalidUnarchiveOperationException”而终止应用程序,原因:“键“resultsSet”的值属于意外类“NSSet”。允许的类是“{(app.Solution)}”。

答案现在很明显,但我可以在任何地方找到它是实现允许的对象列表是一个数组,它需要 NSSet 和自定义对象:解决方案。

if let decodedResultsSet = aDecoder.decodeObject(of: [NSSet.self, Solution.self], forKey: "resultsSet"){

            resultsSet = decodedResultsSet as! Set<Solution>
        }

我希望这可以帮助别人。

于 2020-02-11T10:08:00.143 回答
0

我在使用 iOS 15 / Xcode 13.2 的 Swift 中遇到了同样的问题。我通过在 required init(coder decoder: NSCoder) { } 的 decoder.decodeObject 中简单地添加 NSNumber (警告中列出的违规类)来解决它(我编辑了类名)。MyVar 包含一些数字。

required init(coder decoder: NSCoder) {
    
    myVar = decoder.decodeObject(of: [MyType.self, NSNumber.self], forKey: theKey) as? [MyVar] ?? []
}
于 2022-02-02T21:25:07.023 回答