YYModel
YYModel copied to clipboard
switch to use method `decodeObjectOfClass:forKey:` to decode an object
Hello bireme,
Here is the reason why this pull request happened.
I have a model like this:
@interface HWPerson : NSObject <NSSecureCoding>
@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, strong) NSURL *avatarURL;
@end
@implementation HWPerson
+ (BOOL)supportsSecureCoding {
return YES;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[self yy_modelEncodeWithCoder:aCoder];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
return [self yy_modelInitWithCoder:aDecoder];
}
@end
I'd like to use NSSecureCoding
rather than NSCoding
. Then something unexpected happened. I can NSKeyedArchiver
to save this model to disk successfully, but I cannot read and unarchive it from the disk. There's an error.
After debug, I found it is because the NSURL
property. This property cannot be unarchived in yy_modelInitWithCoder:
with method decodeObjectforKey:
. We have to use decodeObjectOfClass:forKey:
.
Here is the example code to save and read this mode:
- (void)save {
HWPerson *person = [[HWPerson alloc] init];
person.firstName = @"will";
person.lastName = @"chen";
person.age = 28;
person.avatarURL = [NSURL URLWithString:@"https://example.com/avatar.png"];
if (@available(iOS 11, *)) {
NSError *error = nil;
NSData *personData = [NSKeyedArchiver archivedDataWithRootObject:person
requiringSecureCoding:YES
error:&error];
if (!personData) {
NSLog(@"Archiver Failed: %@", error.localizedDescription);
}
error = nil;
BOOL result = [personData writeToFile:[self filePath]
options:0
error:&error];
if (!result) {
NSLog(@"Write to File Failed: %@", error.localizedDescription);
}
} else {
BOOL result = [NSKeyedArchiver archiveRootObject:person toFile:[self filePath]];
if (!result) {
NSLog(@"Write to File Failed");
}
}
}
- (void)read {
if (@available(iOS 11, *)) {
NSError *error = nil;
NSData *data = [NSData dataWithContentsOfFile:[self filePath]];
HWPerson *person = [NSKeyedUnarchiver unarchivedObjectOfClass:HWPerson.class
fromData:data
error:&error];
if (!person) {
NSLog(@"Read from File Failed: %@", error.localizedDescription);
} else {
NSLog(@"%@·%@ is %ld", person.firstName, person.lastName, person.age);
NSLog(@"Avatar URL: %@", person.avatarURL);
}
} else {
HWPerson *person = [NSKeyedUnarchiver unarchiveObjectWithFile:[self filePath]];
if (!person) {
NSLog(@"Read from File Failed");
} else {
NSLog(@"%@·%@ is %ld", person.firstName, person.lastName, person.age);
NSLog(@"Avatar URL: %@", person.avatarURL);
}
}
}
Codecov Report
Merging #302 into master will not change coverage. The diff coverage is
100%
.
@@ Coverage Diff @@
## master #302 +/- ##
=======================================
Coverage 99.28% 99.28%
=======================================
Files 2 2
Lines 1540 1540
=======================================
Hits 1529 1529
Misses 11 11
Impacted Files | Coverage Δ | |
---|---|---|
YYModel/NSObject+YYModel.m | 99.21% <100%> (ø) |
:arrow_up: |
Continue to review full report at Codecov.
Legend - Click here to learn more
Δ = absolute <relative> (impact)
,ø = not affected
,? = missing data
Powered by Codecov. Last update 1230e60...351f45b. Read the comment docs.
In order to conform to NSSecureCoding:
An object that does not override initWithCoder:
can conform to NSSecureCoding without any changes (assuming that it is a subclass of another class that conforms).
An object that does override initWithCoder:
must decode any enclosed objects using the decodeObjectOfClass:forKey:
method. For example:
id obj = [decoder decodeObjectOfClass:[MyClass class] forKey:@"myKey"];
In addition, the class must override the getter for its supportsSecureCoding
property to return YES.
Link: NSSecureCoding