I am having trouble with adopting NSSecureCoding. I encode an array containing objects of my custom class, which adoptsNSSecureCoding properly. When I decode it, passing the classNSArray (which is the class of the object I encoded), it throws an exception. However, when do theexact same thing with an array of strings, it works fine. I fail to see what is the difference between my class and 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;}@endint 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;}- Does this answer your question?Error of Unexpected class while encode/decode an NSArray with NSSecureCodingTT--– TT--2023-12-08 22:14:39 +00:00CommentedDec 8, 2023 at 22:14
3 Answers3
My solution was to usedecodeObjectOfClasses:forKey:
In Swift:
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 } }In Objective-C it would be something like:
[unArchiver decodeObjectOfClasses:allowedClasses forKey:NSKeyedArchiveRootObjectKey]The change in decode object to decode objects solved the above exception for me.
3 Comments
[coder decodeObjectOfClasses:[NSSet setWithObjects:[NSArray class], [MyCustomClass class], nil] forKey:key]; Very poor documentation on Apple's part, but works like a charm!I was really struggling with this for an hour in Swift 5.
My situation was I had a Set of custom Solution objects:
var resultsSet = Set<Solution>()Which conformed to Secure Coding:
static var supportsSecureCoding: Bool{ get{ return true } }Their container object encoded them as an NSSet, because of Secure Coding:
aCoder.encode(resultsSet as NSSet, forKey: "resultsSet")But I always got a complier error during decoding:
if let decodedResultsSet = aDecoder.decodeObject(of: NSSet.self, forKey: "resultsSet"){ resultsSet = decodedResultsSet as! Set<Solution>}Error:
2020-02-11 22:35:06.555015+1300 Exception occurred restoring state value for key 'NS.objects' was of unexpected class 'App.Solution'. Allowed classes are '{(NSSet)}'.2020-02-11 22:35:06.564758+1300 *** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: 'value for key 'NS.objects' was of unexpected class 'App.Solution'. Allowed classes are '{(NSSet)}'.'
If I changed the decodeObject(ofClass: to Solution:
if let decodedResultsSet = aDecoder.decodeObject(of: Solution.self, forKey: "resultsSet"){ resultsSet = decodedResultsSet as! Set<Solution>}I get the error:
2020-02-11 22:33:46.924580+1300 Exception occurred restoring state value for key 'resultsSet' was of unexpected class 'NSSet'. Allowed classes are '{(app.Solution)}'.2020-02-11 22:33:46.933812+1300 *** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: 'value for key 'resultsSet' was of unexpected class 'NSSet'. Allowed classes are '{(app.Solution)}'.'
The answer, which is obvious now, but I could find it anywhere was to realise the allowed object list is an array, and it needs both NSSet and the custom object: Solution.
if let decodedResultsSet = aDecoder.decodeObject(of: [NSSet.self, Solution.self], forKey: "resultsSet"){ resultsSet = decodedResultsSet as! Set<Solution>}Comments
I had the same problem in Swift with iOS 15 / Xcode 13.2.I solved it by simply adding NSNumber (the offending class listed in the warning) in the decoder.decodeObject of required init(coder decoder: NSCoder) { }(I edited the class names). MyVar contains some numbers.
required init(coder decoder: NSCoder) { myVar = decoder.decodeObject(of: [MyType.self, NSNumber.self], forKey: theKey) as? [MyVar] ?? []}Comments
Explore related questions
See similar questions with these tags.

