如何使用 unarchivedObjectOfClass:fromData:error: 解压数据?

Ion*_*tîr 11 objective-c ios ios12

我正在使用unarchiveObjectWithData取消归档数据NSUserDefaults并且它运行良好,但它在 iOS 12.0 中已被弃用。Xcode 建议使用unarchivedObjectOfClass:fromData:error:,但此方法不起作用。

我有一个类的对象数组要取消归档。

我曾尝试使用unarchivedObjectOfClass:fromData:error:, 也unarchivedObjectOfClasses:fromData:error:与所有类(NSArray、NSString、MYCLASS ..)

作品

NSArray *stored = [NSKeyedUnarchiver unarchiveObjectWithData:data];
Run Code Online (Sandbox Code Playgroud)

才不是:

NSArray *stored = [NSKeyedUnarchiver unarchivedObjectOfClass:[MYCLASS class] fromData:data error:&error];
Run Code Online (Sandbox Code Playgroud)

我收到“无法读取数据,因为它的格式不正确。”

Dar*_*ren 19

unarchivedObjectOfClass:fromData:error似乎没有记录,但我已经弄清楚了。在您的情况下,当您取消归档NSArray并假设数组的内容是标准类时,NSString这应该适合您:

NSArray *stored = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSArray class] fromData:data error:&error];
Run Code Online (Sandbox Code Playgroud)

但是,我正在解压缩自定义对象PurchasedSubscription,如果您NSArray包含任何自定义类,这也适用......首先,objectOfClass从方法到解压缩需要是您期望结果的类。

PurchasedSubscription *purchasedSubscription = [NSKeyedUnarchiver unarchivedObjectOfClass:PurchasedSubscription.class fromData:data error:&error];
Run Code Online (Sandbox Code Playgroud)

接下来,您的自定义类需要符合,NSSecureCoding因此将其添加到类的接口中。我假设你已经NSCoding实施了。

@interface PurchasedSubscription : NSObject <NSCoding, NSSecureCoding>

@end
Run Code Online (Sandbox Code Playgroud)

接下来您的课程必须覆盖supportsSecureCoding以确认它受支持

+ (BOOL)supportsSecureCoding
{
    return YES;
}
Run Code Online (Sandbox Code Playgroud)

接下来,在您的initWithCoder:方法中,您需要在解码每个属性时使用decodeObjectOfClass:key:而不是使用decodeObjectForKey,再次将Class参数设置为正在解码的类类型。

- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder
{
    self = [self init];

    if (self)
    {
        ReceiptInfo *receiptInfo = [aDecoder decodeObjectOfClass:[ReceiptInfo class] forKey:@"receiptInfo"];
        return [self initWithReceiptInfo:receiptInfo];
    }

    return self;
}
Run Code Online (Sandbox Code Playgroud)

正如你在这里看到的,这个类还解码另一个自定义类ReceiptInfo,所以我不得不对那个类重复这个过程才能让它全部工作。

现在当我使用

PurchasedSubscription *purchasedSubscription = [NSKeyedUnarchiver unarchivedObjectOfClass:PurchasedSubscription.class fromData:data error:&error];
Run Code Online (Sandbox Code Playgroud)

PurchasedSubscription通过安全地解码类来安全地解码ReceiptInfo类,因为它在解码之前知道在每个步骤中类的类型应该是什么。


对对面的注解NSEncoding。您需要使用该方法

archivedDataWithRootObject:requiringSecureCoding:error:
Run Code Online (Sandbox Code Playgroud)

代替

archivedDataWithRootObject:
Run Code Online (Sandbox Code Playgroud)

有了这个,你不用传入对象类,而是传入实际的对象。就我而言,我像这样创建对象

PurchasedSubscription *validSub = [[PurchasedSubscription alloc] initWithReceiptInfo:latestReceipt];
Run Code Online (Sandbox Code Playgroud)

然后像这样编码

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:validSub requiringSecureCoding:YES error:&error];
Run Code Online (Sandbox Code Playgroud)