archivedDataWithRootObject:始终 returns "nil"

archivedDataWithRootObject: always returns "nil"

我有一个名为 Person 的 class 并创建了一个 Person instance “人”。

Person *person = [Person personWithName:@"Kyle", andAge:15];

然后我尝试使用方法archivedDataWithRootObject:requiringSecureCoding:error:对其进行编码。

NSData *personData = [NSKeyedArchiver archivedDataWithRootObject:person 
                                      requiringSecureCoding:YES error:nil];

但是,personData总是returnsnil。我错过了什么吗?

Person.h

@interface Person : NSObject<NSSecureCoding>
@property (strong, nonatomic) NSString *name;
@property (assign, nonatomic) NSInteger age;
+ (instancetype)personWithName:(NSString *)name andAge:(NSInteger)age;
@end

Person.m

@implementation Person
+ (instancetype)personWithName:(NSString *)name andAge:(NSInteger)age{
    Person *p = [Person new];
    p.name = name;
    p.age = age;
    return p;
}
+ (BOOL)supportsSecureCoding {
    return YES;
}
- (id)initWithCoder:(NSCoder *)coder {
    self = [super initWithCoder:coder]; // error: No visible @interface for 'NSObject' declares the selector 'initWithCoder'
    return self;
}
@end

Update(在 .m 中实现 +supportsSecureCoding 之后):

Class 'Person' has a superclass that supports secure coding, but 'Person' overrides -initWithCoder: and does not override +supportsSecureCoding. The class must implement +supportsSecureCoding and return YES to verify that its implementation of -initWithCoder: is secure coding compliant.

出了什么问题:Person 不符合 NSSecureCoding 标准。如果你玩过 Archiving Custom Class into Data with NSKeyedArchiver(如果是老开发者,he/she 会说 NSCoding,那是第一个想到的事情,但这“几乎是相同”,相同的逻辑)。
这有什么关系?这只是如何将 Person 转换为 NSData 并反转。这是什么逻辑?你想保存它的属性吗?如何?等等

但是,作为开发者你最大的错误就是完全忽略错误参数!

NSData *personData = [NSKeyedArchiver archivedDataWithRootObject:person 
                                      requiringSecureCoding:YES error:nil];

==>

NSError *archiveError
NSData *personData = [NSKeyedArchiver archivedDataWithRootObject:person 
                                      requiringSecureCoding:YES
                                      error:& archiveError];
if (archiveError) {
    NSLog(@"Ooops, got error while archiving: %@", archiveError);
}

那么错误会表明它确实缺少 NSSecureCoding 合规性

查看 Archives and Serializations Programming Guide: Encoding and Decoding Objects 的文档,您将了解如何实现 initWithCoder:(从 NSDataPerson)和 encodeWithCoder:(从 PersonNSData).

应用于您的 class(并将其添加到符合性中:例如 @interface Person : NSObject< NSSecureCoding >):

- (void) encodeWithCoder:(NSCoder *)encoder { 
    [encoder encodeObject:_name forKey:@"name"]; 
    [encoder encodeInteger:_age forKey:@"age"]; 
} 

- (id)initWithCoder:(NSCoder *)coder { 
    self = [super init]; 
    if (self) { 
        _name = [coder decodeObjectForKey:@"name"]; 
        _age = [coder decodeIntegerForKey:@"age"]; 
    } 
    return self; 
}

+ (BOOL)supportsSecureCoding {
    return YES;
}

注意字符串键("name" & "age" 需要与 encode/decode 相同,可以使用 const 等)