在上篇部落格《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類的屬性字串,並以陣列的形式返回。程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
///通過執行時獲取當前物件的所有屬性的名稱,以陣列的形式返回 - (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 ) { ///取出第一個屬性 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方法比較簡單,具體程式碼如下:
1 2 3 4 5 6 |
#pragma mark -- 通過字串來建立該字串的Setter方法,並返回 - (SEL) creatGetterWithPropertyName: (NSString *) propertyName{ //1.返回get方法: oc中的get方法就是屬性的本身 return NSSelectorFromString(propertyName); } |
二、Get方法的執行
接下來要做的是通過Runtime來執行Getter方法,這一塊需要通過方法的簽名來執行Getter方法。在OC的執行時中要執行的方法需要傳入引數或者需要接收返回值時,需要通過方法的簽名來呼叫方法。下面的程式碼就是建立方法的簽名,然後通過簽名來獲取呼叫的物件,在下邊的方中回撥用上述兩個方法在通過方法的簽名來獲取Model屬性的值,具體程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
- (void) displayCurrentModleProperty{ //獲取實體類的屬性名 NSArray *array = [self allPropertyNames]; //拼接引數 NSMutableString *resultString = [[NSMutableString alloc] init]; for (int i = 0; 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的屬性值,呼叫程式碼如下所示:
1 2 3 |
BeautifulGirlModel *beautifulGirl = [BeautifulGirlModel modelWithDictionary:data]; [beautifulGirl displayCurrentModleProperty]; |
執行結果如下,下面的輸出結果是Model中屬性的值。
三、Dictionary的Key與Model的屬性不同的處理方式
有時候會遇到字典的key和Model的屬性不一樣的情況,那麼如何去解決這個問題呢?最簡單的做法是在具體的實體類中去維護一個對映關係方法,通過這個方法我們可以獲取相應的的對映關係。
1.在Model的基類中新增一個返回對映字典的一個方法,然後在子類中進行重寫,這個對映方法在基類中返回nil, 如果子類需要重寫的話就對這個方法進行重寫並返回對映字典。方法如下:
1 2 3 4 |
#pragma 返回屬性和字典key的對映關係 -(NSDictionary *) propertyMapDic{ return nil; } |
2.修改一下我們的便利初始化方法,在有對映字典的情況和沒有對映字典的情況下呼叫的方法是不一樣的,便利初始化方法的程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
- (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的名字一樣的字典,然後呼叫之前的賦值方法,具體程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#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 ) { NSString *key = dicKey[i]; [tempDic setObject:data[key] forKey:propertyMapDic[key]]; } [self assginToPropertyWithDictionary:tempDic]; } |
4.建立一個BadBoyModel, 並重寫propertyMapDic方法,並且在propertyMapDic方法中給出對映關係並返回該對映關係對應的字典。
(1)BadBoyModel的屬性如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// // 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的屬性名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// // 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的屬性不同,下面的迴圈就是要生成測試使用的資料:
1 2 3 4 5 6 7 8 9 10 11 12 |
//生成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並輸出結果,當然之前的程式碼也是可以使用的。
1 2 3 |
BadBoyModel *badBoyModel = [BadBoyModel modelWithDictionary:data1]; [badBoyModel displayCurrentModleProperty]; |
執行輸出結果如下:
今天部落格就到這,至此,Model的基類最基本的方法封裝的也就差不多了,根據具體需求可以在新增新的方法。
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!