參考自:http://www.reibang.com/p/836f07bb468e
- Runtime 是一種面向?qū)ο缶幊陶Z言的運行環(huán)境
- OC最主要的特點就是在程序運行時酿雪,以發(fā)送消息的方式調(diào)用方法(也就是常說的OC是基于運行時的)
一句話概括:通過 Runtime 獲取 model 的屬性列表召川,然后遍歷字典中的 key,如果屬性列表中包含這個 key 則通過 KVC 把字典中對應的 value 賦值到 model 的屬性腕唧。
為什么要利用 Runtime 來進行字典轉(zhuǎn)模型:
- 如果是通過在 model 的 .m 中添加字典轉(zhuǎn)模型的方法,那么枢里,當真正在開發(fā)項目的時候探越,由于有各種不同的 model邢滑,就需要給每個 model 的 .m 都加上字典轉(zhuǎn)模型的方法腐螟。這個方法的思路都是一樣的,只是因為 model 中的屬性略有變化。
- 所以遭垛,我們可以通過為 NSObject 添加一個分類 (因為所有的類(NSProxy 除外)都繼承自 NSObjec)尼桶,利用 Runtime 實現(xiàn)字典轉(zhuǎn)模型的方法,讓所有的 model 都可以使用锯仪。
首先獲取屬性列表泵督。
const char *key = "key";
+ (NSArray *)getPropertyArr {
// 獲取關(guān)聯(lián)對象
NSArray *proArr = objc_getAssociatedObject(self, key);
if (proArr) return proArr; // 如果有值,直接返回
// 調(diào)用運行時方法庶喜,獲取類的屬性列表
/* 成員變量:
* class_copyIvarList(__unsafe_unretained Class cls, unsigned int *outCount)
* 方法:
* class_copyMethodList(__unsafe_unretained Class cls, unsigned int *outCount)
* 屬性:
* class_copyPropertyList(__unsafe_unretained Class cls, unsigned int *outCount)
* 協(xié)議:
* class_copyProtocolList(__unsafe_unretained Class cls, unsigned int *outCount)
*/
unsigned int count = 0;
// retain, creat, copy 需要release
objc_property_t *property_List = class_copyPropertyList([self class], &count);
NSMutableArray *mtArr = [NSMutableArray array];
// 遍歷屬性列表, 獲取屬性名稱
for (int i = 0; i < count; i ++) {
objc_property_t pro = property_List[i];
const char *proName_c = property_getName(pro);
NSString *proName = [NSString stringWithCString:proName_c encoding:NSUTF8StringEncoding];
[mtArr addObject:proName];
}
// 設(shè)置關(guān)聯(lián)對象
objc_setAssociatedObject(self, key, mtArr, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
free(property_List);
return mtArr;
}
關(guān)鍵步驟:
1.
NSArray *proArr = objc_getAssociatedObject(self, key);
如果在程序運行的時候, 模型對象的屬性是不會發(fā)生變化的, 我們在利用這個函數(shù)如果能獲取到關(guān)聯(lián)對象的屬性列表, 就不用再走下面的代碼去利用運行時再去獲取屬性列表了2.
objc_property_t *property_List = class_copyPropertyList([self class], &count);
這句代碼就是真正的利用運行時獲取屬性列表, 這個屬性列表是 C 的結(jié)構(gòu)體指針數(shù)組,我們必須將其遍歷,并利用另外一個函數(shù)將取出結(jié)構(gòu)體指針所指向的結(jié)構(gòu)體中的 C 字符串,也就是屬性名稱3.
const char *proName_c = property_getName(pro);
獲得C字符串后,我們只需要將其轉(zhuǎn)換為 OC 字符串,加到可變數(shù)組中即可4.
objc_setAssociatedObject(self, key, mtArr, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
設(shè)置屬性列表關(guān)聯(lián), 就是把已經(jīng)生成好的屬性列表通過 key 與當前類關(guān)聯(lián)到一起小腊,需要用的時候通過 key 獲取。
獲取到屬性列表后久窟,進行字典轉(zhuǎn)模型秩冈。
+ (instancetype)modelWithDic:(NSDictionary *)dic {
// 實例化當前對象
id objc = [[self alloc] init];
// 獲取self 的屬性列表
NSArray *proArr = [self getPropertyArr];
// 遍歷字典
[dic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
// 判斷 屬性列表中是否包含這個 key
if ([proArr containsObject:key]) {
// 如果包含通過 KVC 賦值到 model
[objc setValue:obj forKey:key];
}
}];
return objc;
}
現(xiàn)在就可以定義一個模型,進行字典轉(zhuǎn)模型了
- (void)viewDidLoad {
[super viewDidLoad];
NSDictionary *dic = @{
@"name": @"小李",
@"title": @"司機"
};
Person *personModel = [Person modelWithDic:dic];
NSLog(@"%@ --- %@", personModel.name, personModel.title);
}
這就是一些第三方框架,例如 YYModel,MJExtension等的核心算法斥扛,希望在用的時候能明白其中的原理入问。
代碼地址:https://github.com/zhifanYoung/json2model-Demo.git