這兩天把Runtime的知識重新理了一遍,把之前做的數(shù)據(jù)持久化(將一個model序列化后存放到userdefault中)又封裝了一遍。
下面是介紹
需求
我們在開發(fā)中,經(jīng)常需要對一些信息進行歸檔化保存。舉個例子枚抵,我們用作登陸的頁面,登陸后需要獲取到一個token
或session ID
. 這個token
在之后所有的request
都是要調(diào)用到的明场。除此之外汽摹,request
可能還需要其他的一些信息,比如用戶的用戶名苦锨,請求類型逼泣,都需要保存。
個人之前的做法舟舒,就是將請求返回的JSON
轉(zhuǎn)化為model
之后拉庶,序列化存成二進制,放入userDefault
中魏蔗。
但是通常model
具有的property
會相當多砍的,如果都去實現(xiàn)NSCoding
的代理,勢必非常繁瑣莺治。
采用runtime
遍歷屬性的方式廓鞠,在 decoder
和encoder
中去實現(xiàn)方法。
代碼及描述
創(chuàng)建兩個類:
-
BaseArchiveModel
—— 所有待序列化model
類的基類谣旁,在該類中實現(xiàn)NSCoding
的delegate
暴露出兩個接口床佳,供他的子類存取時調(diào)用。/**將類的實例保存至沙盒*/ -(void)saveToSandbox; /** 從沙盒中取出類的實例榄审,轉(zhuǎn)化后返回 @return 實例 */ +(instancetype)fetchFromSandbox;
-
ArchiverTool
—— 一個工具類砌们,用runtime
封裝遍歷屬性的方法,在BaseArchiveModel
中的delegate
去實現(xiàn)他搁进。
下面是代碼.
#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);
}
}