How to unarchive data with unarchivedObjectOfClass:fromData:error:?

别来无恙 提交于 2019-12-05 18:50:26

unarchivedObjectOfClass:fromData:error seems to be pretty undocumented, but I have figured it out. In your case as you are unarchiving an NSArray and assuming the contents of the array are standard classes like NSString then this should work for you:

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

However I was unarchiving a custom object PurchasedSubscription and this also applies if your NSArray contains any custom Classes... Firstly the objectOfClass from the method to unarchive needs to be the class of what you are expecting to be the result.

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

Next, your custom class needs to conform to NSSecureCoding so add this to the interface of the class. I assume you already have NSCoding implemented.

@interface PurchasedSubscription : NSObject <NSCoding, NSSecureCoding>

@end

Next your class has to override supportsSecureCoding to confirm it is supported

+ (BOOL)supportsSecureCoding
{
    return YES;
}

Next, in your initWithCoder: method, you need to use decodeObjectOfClass:key: instead of decodeObjectForKey when decoding each property, again setting the Class parameter as the class type of what's being decoded.

- (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;
}

As you can see here, this class also decodes another custom class ReceiptInfo, so I had to repeat this process with that class to get it all to work.

Now when I use

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

it securely decodes the PurchasedSubscription class by securely decoding the ReceiptInfo class as it knows at each step what the class type should be before it decodes it.


A note on the opposite NSEncoding. You need to use the method

archivedDataWithRootObject:requiringSecureCoding:error:

instead of

archivedDataWithRootObject:

With this one, you don't pass in the object class, you pass in the actual object. In my case, I create the object like so

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

and then encode it like this

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:validSub requiringSecureCoding:YES error:&error];
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!