如何使用unarchivedObjectOfClass:fromData:error:取消存档数据?

时间:2019-03-29 14:15:39

标签: ios objective-c ios12

我正在使用unarchiveObjectWithData来对NSUserDefaults中的数据进行取消存档,并且运行良好,但是在iOS 12.0中已弃用。 Xcode建议使用unarchivedObjectOfClass:fromData:error:,但此方法无效。

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

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

作品

NSArray *stored = [NSKeyedUnarchiver unarchiveObjectWithData:data];

不是:

NSArray *stored = [NSKeyedUnarchiver unarchivedObjectOfClass:[MYCLASS class] fromData:data error:&error];

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

2 个答案:

答案 0 :(得分:1)

unarchivedObjectOfClass:fromData:error似乎还没有记载,但我已经弄清楚了。 在您要解压缩NSArray并假设数组内容是NSString之类的标准类的情况下,这应该对您有用:

NSArray *stored = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSArray class] fromData:data error:&error];

但是我取消了对自定义对象PurchasedSubscription的归档,如果您的NSArray包含任何自定义类,这也适用。 首先,从方法到取消归档的objectOfClass必须是您期望得到的结果的类。

PurchasedSubscription *purchasedSubscription = [NSKeyedUnarchiver unarchivedObjectOfClass:PurchasedSubscription.class fromData:data error:&error];

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

@interface PurchasedSubscription : NSObject <NSCoding, NSSecureCoding>

@end

接下来,您的班级必须重写supportsSecureCoding以确认其受支持

+ (BOOL)supportsSecureCoding
{
    return YES;
}

接下来,在您的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;
}

正如您在此处看到的那样,该类还解码了另一个自定义类ReceiptInfo,因此我必须对该类重复此过程才能使所有功能正常工作。

现在使用时

PurchasedSubscription *purchasedSubscription = [NSKeyedUnarchiver unarchivedObjectOfClass:PurchasedSubscription.class fromData:data error:&error];

它通过安全地解码PurchasedSubscription类来安全地解码ReceiptInfo类,因为它在每一步都知道在解码它之前该类的类型。


相反NSEncoding上的注释。您需要使用方法

archivedDataWithRootObject:requiringSecureCoding:error:

代替

archivedDataWithRootObject:

使用此方法,您无需传递对象类,而可以传递实际的对象。 就我而言,我像这样创建对象

PurchasedSubscription *validSub = [[PurchasedSubscription alloc] initWithReceiptInfo:latestReceipt];

然后像这样编码

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:validSub requiringSecureCoding:YES error:&error];

答案 1 :(得分:1)

我遇到了一个问题,并按照@Darren的答案进行操作,但是 unarchivedObjectOfClass 返回 nil ! :(

所以我尝试了很多变化,发现唯一成功的方法就是我的情况:

supportsSecureCoding 属性必须为

NSArray<MyClassConformedToNSObject_NSCoding_NSSecureCoding *> *arrayOfCustomObjects = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSObject class] fromData:data error:&error];