在上篇博客《iOS開發之使用Runtime給Model類賦值》中介紹瞭如何使用運行時在實體類的基類中添加給實體類的屬性賦值的方法,這個方法的前提是字典的Key必須和實體類的Property Name相同,而後經過運行時來生成和執行Setter方法給Model類的屬性賦值。html
經過Runtime來給Model類屬性賦值的好處是多多的,它便於代碼的後期維護,而且提升了開發效率。當你拿到解析後的字典時你不用一個一個的經過key去把字典的值賦值給相應的Model類的屬性,本篇博客中會給出如何去遍歷Model中屬性的值,而且給出字典的Key和Model的屬性名不同的狀況咱們該如何負值。數組
接下來會在上一個博客代碼基礎上在Model基類中添加經過Runtime來遍歷Model類的屬性值。app
1、獲取Model的實體屬性函數
1.要想遍歷Model類的屬性,首先得經過Runtime來獲取該Model類有哪些屬性,輸出Model的全部屬性的值可不像遍歷Dictionary和Array那樣一個for循環搞定的,下面的方法是經過Runtime來獲取Model類的屬性字符串,並以數組的形式返回。代碼以下:post
1 ///經過運行時獲取當前對象的全部屬性的名稱,以數組的形式返回 2 - (NSArray *) allPropertyNames{ 3 ///存儲全部的屬性名稱 4 NSMutableArray *allNames = [[NSMutableArray alloc] init]; 5 6 ///存儲屬性的個數 7 unsigned int propertyCount = 0; 8 9 ///經過運行時獲取當前類的屬性 10 objc_property_t *propertys = class_copyPropertyList([self class], &propertyCount); 11 12 //把屬性放到數組中 13 for (int i = 0; i < propertyCount; i ++) { 14 ///取出第一個屬性 15 objc_property_t property = propertys[i]; 16 17 const char * propertyName = property_getName(property); 18 19 [allNames addObject:[NSString stringWithUTF8String:propertyName]]; 20 } 21 22 ///釋放 23 free(propertys); 24 25 return allNames; 26 }
2.獲取到Model類的屬性方法後須要把屬性字符串生成get方法,咱們能夠執行get方法來獲取Model屬性的值,下方的方法是根據屬性字符串來獲取屬性的getter方法,OC中屬性的getter方法的名字和屬性的名字是一致的,生成getter方法比較簡單,具體代碼以下:測試
1 #pragma mark -- 經過字符串來建立該字符串的Setter方法,並返回 2 - (SEL) creatGetterWithPropertyName: (NSString *) propertyName{ 3 4 //1.返回get方法: oc中的get方法就是屬性的自己 5 return NSSelectorFromString(propertyName); 6 }
2、Get方法的執行atom
接下來要作的是經過Runtime來執行Getter方法,這一塊須要經過方法的簽名來執行Getter方法。在OC的運行時中要執行的方法須要傳入參數或者須要接收返回值時,須要經過方法的簽名來調用方法。下面的代碼就是建立方法的簽名,而後經過簽名來獲取調用的對象,在下邊的方中回調用上述兩個方法在經過方法的簽名來獲取Model屬性的值,具體代碼以下:url
1 - (void) displayCurrentModleProperty{ 2 3 //獲取實體類的屬性名 4 NSArray *array = [self allPropertyNames]; 5 6 //拼接參數 7 NSMutableString *resultString = [[NSMutableString alloc] init]; 8 9 for (int i = 0; i < array.count; i ++) { 10 11 //獲取get方法 12 SEL getSel = [self creatGetterWithPropertyName:array[i]]; 13 14 if ([self respondsToSelector:getSel]) { 15 16 //得到類和方法的簽名 17 NSMethodSignature *signature = [self methodSignatureForSelector:getSel]; 18 19 //從簽名得到調用對象 20 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 21 22 //設置target 23 [invocation setTarget:self]; 24 25 //設置selector 26 [invocation setSelector:getSel]; 27 28 //接收返回的值 29 NSObject *__unsafe_unretained returnValue = nil; 30 31 //調用 32 [invocation invoke]; 33 34 //接收返回值 35 [invocation getReturnValue:&returnValue]; 36 37 [resultString appendFormat:@"%@\n", returnValue]; 38 } 39 } 40 NSLog(@"%@", resultString); 41 42 }
執行上述方法就能夠輸入Model中的屬性的值,下面就在main函數中對Model賦完值後調用上述方法輸出一下Model的屬性值,調用代碼以下所示:spa
1 BeautifulGirlModel *beautifulGirl = [BeautifulGirlModel modelWithDictionary:data]; 2 3 [beautifulGirl displayCurrentModleProperty];
運行結果以下,下面的輸出結果是Model中屬性的值。code
3、Dictionary的Key與Model的屬性不一樣的處理方式
有時候會遇到字典的key和Model的屬性不同的狀況,那麼如何去解決這個問題呢?最簡單的作法是在具體的實體類中去維護一個映射關係方法,經過這個方法咱們能夠獲取相應的的映射關係。
1.在Model的基類中添加一個返回映射字典的一個方法,而後在子類中進行重寫,這個映射方法在基類中返回nil, 若是子類須要重寫的話就對這個方法進行重寫並返回映射字典。方法以下:
1 #pragma 返回屬性和字典key的映射關係 2 -(NSDictionary *) propertyMapDic{ 3 return nil; 4 }
2.修改一下咱們的便利初始化方法,在有映射字典的狀況和沒有映射字典的狀況下調用的方法是不同的,便利初始化方法的代碼以下:
1 - (instancetype)initWithDictionary: (NSDictionary *) data{ 2 { 3 self = [super init]; 4 if (self) { 5 if ([self propertyMapDic] == nil) { 6 [self assginToPropertyWithDictionary:data]; 7 } else { 8 [self assginToPropertyWithNoMapDictionary:data]; 9 } 10 } 11 return self; 12 } 13 }
3.接下來就將實現有映射關係要調用的方法,這個方法就是經過映射關係把字典的key轉換成與property的名字同樣的字典,而後調用以前的賦值方法,具體代碼以下:
1 #pragma 根據映射關係來給Model的屬性賦值 2 -(void) assginToPropertyWithNoMapDictionary: (NSDictionary *) data{ 3 ///獲取字典和Model屬性的映射關係 4 NSDictionary *propertyMapDic = [self propertyMapDic]; 5 6 ///轉化成key和property同樣的字典,而後調用assginToPropertyWithDictionary方法 7 8 NSArray *dicKey = [data allKeys]; 9 10 11 NSMutableDictionary *tempDic = [[NSMutableDictionary alloc] initWithCapacity:dicKey.count]; 12 13 for (int i = 0; i < dicKey.count; i ++) { 14 NSString *key = dicKey[i]; 15 [tempDic setObject:data[key] forKey:propertyMapDic[key]]; 16 } 17 18 [self assginToPropertyWithDictionary:tempDic]; 19 20 }
4.建立一個BadBoyModel, 並重寫propertyMapDic方法,而且在propertyMapDic方法中給出映射關係並返回該映射關係對應的字典。
(1)BadBoyModel的屬性以下:
1 // 2 // BadBoyModel.h 3 // BaseModelProject 4 // 5 // Created by Mr.LuDashi on 15/7/24. 6 // Copyright (c) 2015年 ludashi. All rights reserved. 7 // 8 9 #import "BaseModelObject.h" 10 11 @interface BadBoyModel : BaseModelObject 12 13 @property (nonatomic, copy) NSString *boy1; 14 @property (nonatomic, copy) NSString *boy2; 15 @property (nonatomic, copy) NSString *boy3; 16 @property (nonatomic, copy) NSString *boy4; 17 18 @end
(2)重寫映射方法,映射字典的key是要轉換字典的key, Value是對應Model的屬性名。
1 // 2 // BadBoyModel.m 3 // BaseModelProject 4 // 5 // Created by Mr.LuDashi on 15/7/24. 6 // Copyright (c) 2015年 ludashi. All rights reserved. 7 // 8 9 #import "BadBoyModel.h" 10 11 @implementation BadBoyModel 12 13 #pragma 返回屬性和字典key的映射關係 14 -(NSDictionary *) propertyMapDic{ 15 return @{@"keyBoy1":@"boy1", 16 @"keyBoy2":@"boy2", 17 @"keyBoy3":@"boy3", 18 @"keyBoy4":@"boy4",}; 19 } 20 21 @end
5.在main函數中進行測試
(1)、生成咱們的數值字典,字典的key與要賦值Model的屬性不一樣,下面的循環就是要生成測試使用的數據:
1 //生成Dic的Key與Model的屬性不同的字典。 2 3 NSMutableDictionary *data1 = [[NSMutableDictionary alloc] init]; 4 5 //建立測試適用的字典 6 for(int i = 1; i <= 4; i ++){ 7 NSString *key = [NSString stringWithFormat:@"keyBoy%d", i]; 8 9 NSString *value = [NSString stringWithFormat:@"我是第%d個壞男孩", i]; 10 11 [data1 setObject:value forKey:key]; 12 }
(2) 實例化Model並輸出結果,固然以前的代碼也是可使用的。
1 BadBoyModel *badBoyModel = [BadBoyModel modelWithDictionary:data1]; 2 3 [badBoyModel displayCurrentModleProperty];
運行輸出結果以下:
今天博客就到這,至此,Model的基類最基本的方法封裝的也就差很少了,根據具體需求能夠在添加新的方法