Senseful
Senseful

Reputation: 91681

Resolving `+[NSKeyedUnarchiver unarchiveTopLevelObjectWithData:error:]` deprecation leads to 'data couldn’t be read' error

I have this code and it works:

Foo *foo = [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:data error:&error];

However, it gives me this warning:

'unarchiveTopLevelObjectWithData:error:' is deprecated: first deprecated in iOS 12.0 - Use +unarchivedObjectOfClass:fromData:error: instead

When I try to make that simple replacement with:

Foo *foo = [NSKeyedUnarchiver unarchivedObjectOfClass:[Foo class] fromData:data error:&error];

... it fails with the following error:

The data couldn’t be read because it isn’t in the correct format.

How do I properly replace this deprecated method with a non-deprecated method?

Upvotes: 1

Views: 1304

Answers (1)

Senseful
Senseful

Reputation: 91681

This is probably because your object conforms to NSCoding, but it should be conforming to NSSecureCoding.

If you look at the documentation for unarchivedObjectOfClass:fromData:error:, you'll notice it says:

Important
Make sure you have adopted NSSecureCoding in the types you decode. If any call to a decode-prefixed method fails, the default decodingFailurePolicy sets the error rather than throwing an exception. In this case, the current and all subsequent decode calls return 0 or nil.

Thus you'll need to do the following to switch over to the un-deprecated function:

  1. Switch the function from [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:data error:&error] to [NSKeyedUnarchiver unarchivedObjectOfClass:[Foo class] fromData:data error:&error], as the deprecation warning says.
  2. Support secure coding:

    1. Switch your conformance from NSCoding to NSSecureCoding for your top-level object.
    2. Add the property:

      @property (class, readonly) BOOL supportsSecureCoding;
      
    3. Implement the method:

      + (BOOL)supportsSecureCoding {
          return YES;
      }
      
    4. If your object has any other properties that are NSCoding repeat all these steps for them so they end up conforming to NSSecureCoding. For example, if there was a property @property (nonatomic, strong) Bar *bar; on your Foo object that is being encoded, you'd need to ensure that Bar also conforms to NSSecureCoding and not just NSCoding.

  3. (Optional) Change your encoding call to require secure coding (i.e. the second parameter can be YES):

    [NSKeyedArchiver archivedDataWithRootObject:self requiringSecureCoding:YES error:&error];
    

It seems like Apple wants people to switch from NSCoding to NSSecureCoding, and the problem above would have been more obvious to resolve if NSCoding was deprecated too.

Upvotes: 2

Related Questions