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];