NSKeyedUnarchiver not working with simple arrays in Catalina (macOS 10.15)

I have an app that recently started building/running under Catalina and its simple state preservation/restoration code has suddenly stopped working.


The code archives an array of custom objects into an NSData blob that gets saved somewhere. Later, that data is decoded back into the array which is used to restore the state.


Distilling the problem, I've created the following example:


#define SECURE 1
#if !SECURE
  // The unsecure example
  UnsecureObject* bonnie = [UnsecureObject new];
  bonnie.property = @"Bonnie Elizabeth Parker";
  UnsecureObject* clyde = [UnsecureObject new];
  clyde.property = @"Clyde Champion Barrow";
  NSArray<unsecureobject*>* rootObject = @[ bonnie, clyde ];
#endif
#if SECURE
  // Secure example
  SecureObject* francis = [SecureObject new];
  francis.property = @"Francis Crick";
  SecureObject* james = [SecureObject new];
  james.property = @" James Watson";
  NSArray<secureobject*>* rootObject = @[ francis, james ];
#endif

  // Encode an array of objects into a data blob
  NSError* error = nil;
  NSData* data = [NSKeyedArchiver archivedDataWithRootObject:rootObject requiringSecureCoding:SECURE error:&error];
  if (error!=nil)
  @throw error;

  // Decode the data back into an array
  NSArray* roundTrip = [NSKeyedUnarchiver unarchivedObjectOfClass:NSArray.class fromData:data error:&error];
  if (error!=nil)
  @throw error;


This works fine in Mojave. In Catalina, the unarchivedObjectOfClass method results in an error:


(lldb) po error
Error Domain=NSCocoaErrorDomain Code=4864 "value for key 'NS.objects' was of unexpected class 'SecureObject'. Allowed classes are '{(
    NSArray
)}'." UserInfo={NSDebugDescription=value for key 'NS.objects' was of unexpected class 'SecureObject'. Allowed classes are '{(
    NSArray
)}'.}

I thought it might be a new "secure coding" requirement, but as you can see the problem occurs regardless of whether the objects in the graph support secure coding or note.


Any suggestions?


(And BTW, where did the documentation for secure coding go? I distinctly remember, years ago, an extensive guide on secure coding describing exactly how to use it and its coding requirements. Now, no matter what I search for, I can only find the legacy "archive and serialization" guide that makes no mention of NSSecureCoding. And, of course, the NSSecureCoding API page explains almost nothing.)

Answered by galad87 in 403369022

You have to use unarchivedObjectOfClasses: and specify all the classes of the objects inside the NSArray too.

Accepted Answer

You have to use unarchivedObjectOfClasses: and specify all the classes of the objects inside the NSArray too.

In addition, if the collection contains collections, you must include the classes for those objects as well. Since this was an array of dictionaries, some containing set objects, this turned out to be pretty annoying.


Furthermore, the same rule applies to decoding individual secure objects using -decodeObjectOfClass:forKey: too.


So it would all seem to be working now, but gosh it would have been nice if this was documented somewhere.

NSKeyedUnarchiver not working with simple arrays in Catalina (macOS 10.15)
 
 
Q