YYModel icon indicating copy to clipboard operation
YYModel copied to clipboard

switch to use method `decodeObjectOfClass:forKey:` to decode an object

Open ihomway opened this issue 6 years ago • 2 comments

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

ihomway avatar Dec 04 '18 16:12 ihomway

Codecov Report

Merging #302 into master will not change coverage. The diff coverage is 100%.

Impacted file tree graph

@@           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.

codecov-io avatar Dec 04 '18 16:12 codecov-io

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

ihomway avatar Dec 05 '18 02:12 ihomway