基本原理 利用 runtime 原理,獲取模型中所有實例變數列表,根據實例變數以此獲取模型中成員變數的名稱和屬性類型,區分Foundation和自定義屬性,需要對NSDictionary和NSArray類型做單獨處理。 下麵代碼是一個簡單的原理實現Demo,真正的框架中需要考慮很多問題,例如可以設置 ...
基本原理
利用 runtime 原理,獲取模型中所有實例變數列表,根據實例變數以此獲取模型中成員變數的名稱和屬性類型,區分Foundation和自定義屬性,需要對NSDictionary和NSArray類型做單獨處理。
下麵代碼是一個簡單的原理實現Demo,真正的框架中需要考慮很多問題,例如可以設置只有某個數組中的屬性名才允許進行字典和模型的轉換,將屬性名換為其他key去字典中取值,白名單,黑名單等等設置
+ (instancetype)modelWithDict:(NSDictionary *)dict { id objc = [[self alloc] init]; unsigned int count = 0; Ivar *ivarList = class_copyIvarList(self, &count); for (int i = 0; i < count; i++) { // 實例變數 Ivar ivar = ivarList[i]; // 獲取成員屬性名 NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)]; NSString *key = [ivarName substringFromIndex:1]; id value = dict[key]; if (value == nil) { continue; } // 獲得成員變數的類型 NSString *ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)]; NSLog(@"ivar - %@, type - %@", ivarName, ivarType); ivarType = [ivarType stringByReplacingOccurrencesOfString:@"\"" withString:@""]; ivarType = [ivarType stringByReplacingOccurrencesOfString:@"@" withString:@""]; if ([value isKindOfClass:[NSDictionary class]]) { Class modelClass = NSClassFromString(ivarType); value = [modelClass modelWithDict:value]; } else if ([value isKindOfClass:[NSArray class]]) { if ([self respondsToSelector:@selector(arrayContainModelClass)]) { NSString *type = [self arrayContainModelClass][key]; Class classModel = NSClassFromString(type); NSMutableArray *arrM = [NSMutableArray array]; for (NSDictionary *dict in value) { id model = [classModel modelWithDict:dict]; if (model) { [arrM addObject:model]; } } value = arrM; } } if (value) { [objc setValue:value forKey:key]; } } return objc; }
常用的 JSON 模型轉換庫
- YYModel:支持自動的 JSON/Model 轉換,支持定義映射過程。API 簡潔,功能也比較簡單。
- JSONModel:一個 JSON 模型轉換庫,有著比較簡潔的介面。Model 需要繼承自 JSONModel。
- Mantle:Github 官方團隊開發的 JSON 模型轉換庫,Model 需要繼承自 MTLModel。
- MJExtension:國內開發者"小碼哥"開發的 JSON 模型庫,號稱性能超過 JSONModel 和 Mantle,使用簡單無侵入。
性能、易用性,無浸入性
根據 ibireme 的測試結果:
-
Mantle 在各個測試中,性能都是最差的
-
JSONModel 和 MJExtension 性能相差不多,但都比 Mantle 性能高。
-
YYModel 性能高出其他幾個庫一個數量級,接近手寫代碼的效率。
-
YYModel、MJExtension 都是採用 Category 方式來實現功能,比較靈活,無侵入
-
如果數據量在很小的時候,其實沒有可比性的,就好比100ms 和 300ms 的差距,用戶是感知不到的,最重要的還是框架的易用性,擴展性,容錯性,和無侵入性。
-
如果對性能、網路流量等有更高的要求,就不要再用 JSON 了,建議改用 protobuf/FlatBuffers 這樣的方案。JSON 轉換再怎麼優化,在性能和流量方面還是遠差於二進位格式的。
-
進行對象類型檢查,避免將錯誤的對象類型賦值到屬性,以避免潛在的 Crash 問題。 YYModel 會嘗試自動轉換,轉換失敗時留空。對部分對象進行自動轉換(比如 NSString 和 NSNumber 之間的轉換)
-
具體容錯處理,可能沒有框架的設計者有自己不同的考慮,就是想讓用戶自己去做容錯處理。