序列化:NSCoding,NSSecureCoding,NSKeyedArchiver,NSKeyedUnarchiver,NSUserDefault

24 8月

通常存储时不会存储明文,而是存储二进制流。NSCoding可以实现序列化和反序列化,将object转成二进制流。转换过程中用key来保证数据的正确性。

  • NSCoding
  • NSSecureCoding
  • NSKeyedArchiver,NSKeyedUnarchiver
  • NSUserDefault

NSCoding

NSCoding是个协议,需要实现两个方法,看名字就知道一个是encode一个是decode:

- (void)encodeWithCoder:(NSCoder *)aCoder;
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder;

NSSecureCoding

通常我们直接用系统提供的NSSecureCoding,它继承自NSCoding,多了个supportsSecureCoding,能保证encode和decode的安全。

序列化对象:

@interface ListItem : NSObject <NSSecureCoding>

// 实现序列化
- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.shopId forKey:@"shopId"];
    [aCoder encodeObject:self.picUrl forKey:@"picUrl"];
    ...
}

// 实现反序列化
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    if (self) {
        self.shopId = [aDecoder decodeObjectForKey:@"shopId"];    // 处理对象和 key 的关系
        self.picUrl = [aDecoder decodeObjectForKey:@"picUrl"];
        ...
    }
    return self;
}

+ (BOOL)supportsSecureCoding {
    return YES;
}

NSKeyedArchiver,NSKeyedUnarchiver

上面这样处理完对象和key之间的关系后,就可以用NSKeyedArchiver和NSKeyedUnarchiver来序列化和反序列化:

NSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachePath = [pathArray firstObject];
NSFileManager *fileManager = [NSFileManager defaultManager];

// 创建文件夹
NSString *dataPath = [cachePath stringByAppendingPathComponent:@"SampleData"];
NSError *creatError;
[fileManager createDirectoryAtPath:dataPath withIntermediateDirectories:YES attributes:nil error:&creatError];

// 序列化后保持到本地
NSString *listDataPath = [dataPath stringByAppendingPathComponent:@"list"];
NSData *listData = [NSKeyedArchiver archivedDataWithRootObject:array requiringSecureCoding:YES error:nil];
[fileManager createFileAtPath:listDataPath contents:listData attributes:nil];
    
// 从本地读取数据反序列化
NSData *readListData = [fileManager contentsAtPath:listDataPath];
id unarchiveObj = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithObjects:[NSArray class], [ListItem class], nil] fromData:readListData error:nil];

NSUserDefault

NSKeyedArchiver/NSKeyedUnarchiver能处理复杂的object,但有时我们只需要存储一些轻量级的数据(例如数字,字符串等),只需要最简单的键值对就能完成需求。系统提供NSUserDefault来存储一些用户偏好信息,文件会自动保存到/Library/Preferences目录下。

它相比NSKeyedArchiver/NSKeyedUnarchiver是更上层的封装,我们只需将数据按键值对形式存储,然后根据key直接读取数据。

// 简单数据存储到 /Library/Preferences 目录下
[[NSUserDefaults standardUserDefaults] setObject:@"Jack" forKey:@"name"];
NSString *myName = [[NSUserDefaults standardUserDefaults] stringForKey:@"name"];

[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"hasRead"];
BOOL hasRead = [[NSUserDefaults standardUserDefaults] boolForKey:@"hasRead"];

总结:比较大的数据用NSKeyedArchiver/NSKeyedUnarchiver保存到本地,小数据用NSUserDefault读写更方便。

发表评论

电子邮件地址不会被公开。 必填项已用*标注