在上篇博客《iOS開發之使用Runtime給Model類賦值》中介紹了如何使用運行時在實體類的基類中添加給實體類的屬性賦值的方法,這個方法的前提是字典的Key必須和實體類的Property Name相同,然後通過運行時來生成和執行Setter方法給Model類的屬性賦值。
通過Runtime來給Model類屬性賦值的好處是多多的,它便於代碼的後期維護,並且提高了開發效率。當你拿到解析後的字典時你不用一個一個的通過key去把字典的值賦值給相應的Model類的屬性,本篇博客中會給出如何去遍歷Model中屬性的值,並且給出字典的Key和Model的屬性名不一樣的情況我們該如何負值。
接下來會在上一個博客代碼基礎上在Model基類中添加通過Runtime來遍歷Model類的屬性值。
一、獲取Model的實體屬性
1.要想遍歷Model類的屬性,首先得通過Runtime來獲取該Model類有哪些屬性,輸出Model的所有屬性的值可不像遍歷Dictionary和Array那樣一個for循環搞定的,下面的方法是通過Runtime來獲取Model類的屬性字符串,並以數組的形式返回。代碼如下:
///通過運行時獲取當前對象的所有屬性的名稱,以數組的形式返回 - (NSArray *) allPropertyNames{ ///存儲所有的屬性名稱 NSMutableArray *allNames = [[NSMutableArray alloc] init]; ///存儲屬性的個數 unsigned int propertyCount = 0; ///通過運行時獲取當前類的屬性 objc_property_t *propertys = class_copyPropertyList([self class], &propertyCount); //把屬性放到數組中 for (int i = 0; i < propertyCount; i ++) { ///取出第一個屬性 objc_property_t property = propertys[i]; const char * propertyName = property_getName(property); [allNames addObject:[NSString stringWithUTF8String:propertyName]]; } ///釋放 free(propertys); return allNames; }
2.獲取到Model類的屬性方法後需要把屬性字符串生成get方法,我們可以執行get方法來獲取Model屬性的值,下方的方法是根據屬性字符串來獲取屬性的getter方法,OC中屬性的getter方法的名字和屬性的名字是一致的,生成getter方法比較簡單,具體代碼如下:
#pragma mark -- 通過字符串來創建該字符串的Setter方法,並返回 - (SEL) creatGetterWithPropertyName: (NSString *) propertyName{ //1.返回get方法: oc中的get方法就是屬性的本身 return NSSelectorFromString(propertyName); }
二、Get方法的執行
接下來要做的是通過Runtime來執行Getter方法,這一塊需要通過方法的簽名來執行Getter方法。在OC的運行時中要執行的方法需要傳入參數或者需要接收返回值時,需要通過方法的簽名來調用方法。下面的代碼就是創建方法的簽名,然後通過簽名來獲取調用的對象,在下邊的方中回調用上述兩個方法在通過方法的簽名來獲取Model屬性的值,具體代碼如下:
- (void) displayCurrentModleProperty{ //獲取實體類的屬性名 NSArray *array = [self allPropertyNames]; //拼接參數 NSMutableString *resultString = [[NSMutableString alloc] init]; for (int i = 0; i < array.count; i ++) { //獲取get方法 SEL getSel = [self creatGetterWithPropertyName:array[i]]; if ([self respondsToSelector:getSel]) { //獲得類和方法的簽名 NSMethodSignature *signature = [self methodSignatureForSelector:getSel]; //從簽名獲得調用對象 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; //設置target [invocation setTarget:self]; //設置selector [invocation setSelector:getSel]; //接收返回的值 NSObject *__unsafe_unretained returnValue = nil; //調用 [invocation invoke]; //接收返回值 [invocation getReturnValue:&returnValue]; [resultString appendFormat:@"%@\n", returnValue]; } } NSLog(@"%@", resultString); }
執行上述方法就可以輸入Model中的屬性的值,下面就在main函數中對Model賦完值後調用上述方法輸出一下Model的屬性值,調用代碼如下所示:
BeautifulGirlModel *beautifulGirl = [BeautifulGirlModel modelWithDictionary:data]; [beautifulGirl displayCurrentModleProperty];
運行結果如下,下面的輸出結果是Model中屬性的值。
三、Dictionary的Key與Model的屬性不同的處理方式
有時候會遇到字典的key和Model的屬性不一樣的情況,那麼如何去解決這個問題呢?最簡單的做法是在具體的實體類中去維護一個映射關系方法,通過這個方法我們可以獲取相應的的映射關系。
#pragma 返回屬性和字典key的映射關系 -(NSDictionary *) propertyMapDic{ return nil; }
2.修改一下我們的便利初始化方法,在有映射字典的情況和沒有映射字典的情況下調用的方法是不一樣的,便利初始化方法的代碼如下:
- (instancetype)initWithDictionary: (NSDictionary *) data{ { self = [super init]; if (self) { if ([self propertyMapDic] == nil) { [self assginToPropertyWithDictionary:data]; } else { [self assginToPropertyWithNoMapDictionary:data]; } } return self; } }
3.接下來就將實現有映射關系要調用的方法,這個方法就是通過映射關系把字典的key轉換成與property的名字一樣的字典,然後調用之前的賦值方法,具體代碼如下:
#pragma 根據映射關系來給Model的屬性賦值 -(void) assginToPropertyWithNoMapDictionary: (NSDictionary *) data{ ///獲取字典和Model屬性的映射關系 NSDictionary *propertyMapDic = [self propertyMapDic]; ///轉化成key和property一樣的字典,然後調用assginToPropertyWithDictionary方法 NSArray *dicKey = [data allKeys]; NSMutableDictionary *tempDic = [[NSMutableDictionary alloc] initWithCapacity:dicKey.count]; for (int i = 0; i < dicKey.count; i ++) { NSString *key = dicKey[i]; [tempDic setObject:data[key] forKey:propertyMapDic[key]]; } [self assginToPropertyWithDictionary:tempDic]; }
4.創建一個BadBoyModel, 並重寫propertyMapDic方法,並且在propertyMapDic方法中給出映射關系並返回該映射關系對應的字典。
(1)BadBoyModel的屬性如下:
// // BadBoyModel.h // BaseModelProject // // Created by Mr.LuDashi on 15/7/24. // Copyright (c) 2015年 ludashi. All rights reserved. // #import "BaseModelObject.h" @interface BadBoyModel : BaseModelObject @property (nonatomic, copy) NSString *boy1; @property (nonatomic, copy) NSString *boy2; @property (nonatomic, copy) NSString *boy3; @property (nonatomic, copy) NSString *boy4; @end
(2)重寫映射方法,映射字典的key是要轉換字典的key, Value是對應Model的屬性名。
// // BadBoyModel.m // BaseModelProject // // Created by Mr.LuDashi on 15/7/24. // Copyright (c) 2015年 ludashi. All rights reserved. // #import "BadBoyModel.h" @implementation BadBoyModel #pragma 返回屬性和字典key的映射關系 -(NSDictionary *) propertyMapDic{ return @{@"keyBoy1":@"boy1", @"keyBoy2":@"boy2", @"keyBoy3":@"boy3", @"keyBoy4":@"boy4",}; } @end
5.在main函數中進行測試
(1)生成我們的數值字典,字典的key與要賦值Model的屬性不同,下面的循環就是要生成測試使用的數據:
//生成Dic的Key與Model的屬性不一樣的字典。 NSMutableDictionary *data1 = [[NSMutableDictionary alloc] init]; //創建測試適用的字典 for(int i = 1; i <= 4; i ++){ NSString *key = [NSString stringWithFormat:@"keyBoy%d", i]; NSString *value = [NSString stringWithFormat:@"我是第%d個壞男孩", i]; [data1 setObject:value forKey:key]; }
(2) 實例化Model並輸出結果,當然之前的代碼也是可以使用的。
BadBoyModel *badBoyModel = [BadBoyModel modelWithDictionary:data1]; [badBoyModel displayCurrentModleProperty];
運行輸出結果如下:
今天博客就到這,至此,Model的基類最基本的方法封裝的也就差不多了,根據具體需求可以在添加新的方法
作者:青玉伏案
出處:http://www.cnblogs.com/ludashi/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
如果文中有什麼錯誤,歡迎指出。以免更多的人被誤導。