自定義model 無法直接存入沙盒,需要先將 model 轉(zhuǎn)成 NSData,然后將 data 存入沙盒。讀取的時候也是讀到 NSData,然后將 data 轉(zhuǎn)成 model。所以自定義 model 必須遵循 NSCoding 協(xié)議。
1.model 簽NSCoding 協(xié)議,并實現(xiàn)協(xié)議方
- (void)encodeWithCoder:(nonnull NSCoder *)aCoder {
[aCoder encodeObject:_name forKey:@"name"];
[aCoder encodeObject:@(_num) forKey:@"num"];
[aCoder encodeObject:@(_sex) forKey:@"sex"];
}
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {
self = [super init];
if (self) {
_name = [aDecoder decodeObjectForKey:@"name"];
_num = [[aDecoder decodeObjectForKey:@"num"] intValue];
_sex = [[aDecoder decodeObjectForKey:@"sex"] intValue];
}
return self;
}
2.自定義讀取、保存方法
+(CustomModel *)createCustomModel
{
id modelId = [[NSUserDefaults standardUserDefaults] objectForKey:KSaveCustomModelKey];
if (modelId && [modelId isKindOfClass:[NSData class]]) {
id model = [NSKeyedUnarchiver unarchiveObjectWithData:(NSData *)modelId];
if (model && [model isKindOfClass:[CustomModel class]]) {
return (CustomModel *)model;
}
}
return [[CustomModel alloc] init];
}
- (void)saveCustomModel
{
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
if (data) {
[[NSUserDefaults standardUserDefaults] setObject:data forKey:KSaveCustomModelKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
通過以上方法就可以實現(xiàn)自定義 model 的數(shù)據(jù)持久化,但是當(dāng) model 的屬性太多就會導(dǎo)致寫好多重復(fù)代碼,下面我們可以使用 runtime 做一下簡單優(yōu)化。
3.優(yōu)化
// 使用 runtime 遍歷 model 的所有屬性
+ (void)goThroughAllProperty:(id)object propertyBlock:(void(^)(NSString *propertyName))propertyBlcok {
u_int count;
objc_property_t *propertyList = class_copyPropertyList([object class], &count);
for (int i = 0; i < count; i++) {
const char *propertyChar = property_getName(propertyList[i]);
NSString *propertyName = [NSString stringWithUTF8String:propertyChar];
if (propertyBlcok) {
propertyBlcok(propertyName);
}
}
free(propertyList);
}
#pragma mark NSCoding protocol
- (void)encodeWithCoder:(nonnull NSCoder *)aCoder {
__weak typeof(self) weakself = self;
[[self class] goThroughAllProperty:self propertyBlock:^(NSString *propertyName) {
id value = [weakself valueForKey:propertyName];
[aCoder encodeObject:value forKey:propertyName];
}];
}
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {
self = [super init];
if (self) {
__weak typeof(self) weakself = self;
[[self class] goThroughAllProperty:self propertyBlock:^(NSString *propertyName) {
id value = [aDecoder decodeObjectForKey:propertyName];
[weakself setValue:value forKey:propertyName];
}];
}
return self;
}
這樣寫可以節(jié)省很多不必要的重復(fù),并且可以避免出錯和數(shù)據(jù)丟失。