这两天把Runtime的知识重新理了一遍,把之前做的数据持久化(将一个model序列化后存放到userdefault中)又封装了一遍。
下面是介绍
需求
我们在开发中,经常需要对一些信息进行归档化保存。举个例子,我们用作登陆的页面,登陆后需要获取到一个token
或session ID
. 这个token
在之后所有的request
都是要调用到的。除此之外,request
可能还需要其他的一些信息,比如用户的用户名,请求类型,都需要保存。
个人之前的做法,就是将请求返回的JSON
转化为model
之后,序列化存成二进制,放入userDefault
中。
但是通常model
具有的property
会相当多,如果都去实现NSCoding
的代理,势必非常繁琐。
采用runtime
遍历属性的方式,在 decoder
和encoder
中去实现方法。
代码及描述
创建两个类:
-
BaseArchiveModel
—— 所有待序列化model
类的基类,在该类中实现NSCoding
的delegate
暴露出两个接口,供他的子类存取时调用。/**将类的实例保存至沙盒*/ -(void)saveToSandbox; /** 从沙盒中取出类的实例,转化后返回 @return 实例 */ +(instancetype)fetchFromSandbox;
-
ArchiverTool
—— 一个工具类,用runtime
封装遍历属性的方法,在BaseArchiveModel
中的delegate
去实现他。
下面是代码.
#import "BaseArchiveModel.h"
#import <objc/message.h>
@implementation BaseArchiveModel
-(void)encodeWithCoder:(NSCoder *)aCoder {
[ArchiverTool encodeWithClassName:[self class] modelInstance:self aCoder:aCoder];
}
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
[ArchiverTool decodeWithClassName:[self class] modelInstance:self aCoder:aDecoder];
}
return self;
}
-(void)saveToSandbox {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
NSLog(@"存入沙盒的属性名 = %@",NSStringFromClass([self class]));
[[NSUserDefaults standardUserDefaults] setObject:data forKey:NSStringFromClass([self class])];
[[NSUserDefaults standardUserDefaults] synchronize];
}
+(instancetype)fetchFromSandbox {
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSData *tempData = [user objectForKey:NSStringFromClass([self class])];
NSLog(@"沙盒中取出的属性名 = %@",NSStringFromClass([self class]));
id final = [NSKeyedUnarchiver unarchiveObjectWithData:tempData];
return final;
}
@end
// -------------------------------
@implementation ArchiverTool
+(void)encodeWithClassName:(Class)classname modelInstance:(id)instance aCoder:(NSCoder*)aCoder {
unsigned int count = 0;
Ivar *var = class_copyIvarList(classname, &count);
for (int i = 0; i <count; i++) {
Ivar property = var[i];
const char* char_f =ivar_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:char_f];
id propertyValue = [instance valueForKey:(NSString *)propertyName];
NSLog(@"属性 %@,值 %@",propertyName,propertyValue);
[aCoder encodeObject:propertyValue forKey:propertyName];
}
}
+(void)decodeWithClassName:(Class)classname modelInstance:(id)instance aCoder:(NSCoder*)aCoder {
unsigned int count = 0;
Ivar *var = class_copyIvarList(classname, &count);
for (int i = 0; i <count; i++) {
Ivar property = var[i];
const char* char_f =ivar_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:char_f];
[instance setValue:[aCoder decodeObjectForKey:propertyName] forKey:propertyName];
}
}
@end
另一种遍历的方法代码(大同小异)
+(void)getKeyAndValueFromModel:(id)myModel {
NSMutableDictionary *props = [NSMutableDictionary dictionary];
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList([myModel class], &outCount);
for (i = 0; i<outCount; i++){
objc_property_t property = properties[i];
const char* char_f =property_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:char_f];
id propertyValue = [myModel valueForKey:(NSString *)propertyName];
NSLog(@"props>>>>>>>>>>>>>>>>>>>%@",props);
}
}