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

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

我有这段代码并且有效:

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

但是,它给了我这个警告:

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

当我尝试用以下方法进行简单替换时:

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

...失败并出现以下错误:

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

如何使用未弃用的方法正确替换此已弃用的方法?

这可能是因为你的对象符合NSCoding,但它应该符合NSSecureCoding

如果您查看 unarchivedObjectOfClass:fromData:error: 的 documentation,您会注意到它说:

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.

因此您需要执行以下操作以切换到未弃用的函数:

  1. 如弃用警告所述,将函数从 [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:data error:&error] 切换到 [NSKeyedUnarchiver unarchivedObjectOfClass:[Foo class] fromData:data error:&error]
  2. 支持安全编码:

    1. 将顶级对象的合规性从 NSCoding 切换到 NSSecureCoding
    2. 添加属性:

      @property (class, readonly) BOOL supportsSecureCoding;
      
    3. 实现方法:

      + (BOOL)supportsSecureCoding {
          return YES;
      }
      
    4. 如果您的对象具有 NSCoding 的任何其他属性,请为它们重复所有这些步骤,使它们最终符合 NSSecureCoding。例如,如果正在编码的 Foo 对象上有 属性 @property (nonatomic, strong) Bar *bar;,则需要确保 Bar 也符合 NSSecureCoding而不仅仅是 NSCoding.

  3. (可选)更改您的编码调用以要求安全编码(即第二个参数可以是 YES):

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

Apple 似乎希望人们从 NSCoding 切换到 NSSecureCoding,如果 NSCoding 也被弃用,上述问题将更容易解决。