本篇博客算是給網絡緩存打個基礎吧,本篇博客先給出簡單也是最容易使用的把字典轉成實體類的方法,然後在給出如何使用Runtime來給Model實體類賦值。本篇博客會介紹一部分,主要是字典的key與Model的屬性名相同時,使用Runtime來進行賦值,下篇博客會給出字典key的值和Model的名字不同時的解決方案,並給出使用Runtime打印實體類屬性值的方式。
當然你可以使用KVC的setValuesForKeysWithDictionary:方法,下面的方法也是一種解決方案。如果使用setValuesForKeysWithDictionary:方法,則Model基類中必須得重寫下面的方法,不然如果遇到字典的Key和modle的屬性不對應的情況則會出現程序崩潰的情況。
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
}
iOS開發中的Runtime可謂是功能強大,同時Runtime使用起來也是非常靈活的,今天博客的內容主要就是使用到一丁點的Runtime的東西。好廢話不多說了進入今天的整體。
一、創建我們的測試工程
在本測試工程中使用不到iOS開發的UI部分,所以我們就創建一個基於系統控制台的工程,主調用代碼當然是放到main函數中了,Project創建過程如下圖所示,Create new project -> OS X -> Application -> Command Line Tool ->一路next即可
二、創建我們的測試數據
1.首先使用for循環創建一個字典,當然字典的key和value在這是有規律的,下面的for循環是創建我們的測試數據,如果在有網絡請求的狀態下,該測試字典的來源就是你從網絡請求的JOSN解析出來的字典,在這兒沒有進行網絡請求,因為網絡請求不是本篇博客的重點,所以就使用for循環生成一個測試字典以供使用。創建測試字典的代碼如下,改代碼的位置放在main函數當中:
1 NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithCapacity:11];
2
3 //創建測試適用的字典
4 for(int i = 0; i <= 10; i ++){
5 NSString *key = [NSString stringWithFormat:@"girl%d", i];
6
7 NSString *value = [NSString stringWithFormat:@"我是第%d個女孩", i];
8
9 [data setObject:value forKey:key];
10 }
上述代碼生成字典,打印結果如下,可以看出字典是無序的,接下來就將data這個字典作為我們網絡請求JSON解析後的字典來使用。
1 2015-07-20 22:33:15.742 BaseModelProject[65321:3224966] data = {
2 girl0 = "我是第0個女孩";
3 girl1 = "我是第1個女孩";
4 girl10 = "我是第10個女孩";
5 girl2 = "我是第2個女孩";
6 girl3 = "我是第3個女孩";
7 girl4 = "我是第4個女孩";
8 girl5 = "我是第5個女孩";
9 girl6 = "我是第6個女孩";
10 girl7 = "我是第7個女孩";
11 girl8 = "我是第8個女孩";
12 girl9 = "我是第9個女孩";
13 }
三、創建data字典對應的實體類
接下來將會創建Data字典對應的實體類,首先將會實現實體類的屬性名和字典的key值一致的情況,然後在下篇博客中將會實現如何把不同key值的字典轉換成實體類的屬性。
1、首先我們先創建一個實體類,這個實體類要繼承與實體基類,因為一些公用的方法是在實體基類中進行編寫的,如便利構造器,便利初始化方法,把字典轉成Model屬性等方法回被抽象到這個基類當中。創建實體類如下圖所示,創建類的時候選中創建的基類即可:
2. 這個實體類的命名為:BeautifulGirlModel,下面是BeautifulGirlModel中的屬性,屬性的名字和字典key的值相同,如下所示,BaseModelObject是之前創建的基類,BaseModelObject繼承與NSObject即可。
1 //
2 // BeautifulGirlModel.h
3 // BaseModelProject
4 //
5 // Created by Mr.LuDashi on 15/7/20.
6 // Copyright (c) 2015年 ludashi. All rights reserved.
7 //
8
9 #import "BaseModelObject.h"
10
11 @interface BeautifulGirlModel : BaseModelObject
12
13 @property (nonatomic, copy) NSString *girl0;
14 @property (nonatomic, copy) NSString *girl1;
15 @property (nonatomic, copy) NSString *girl2;
16 @property (nonatomic, copy) NSString *girl3;
17 @property (nonatomic, copy) NSString *girl4;
18 @property (nonatomic, copy) NSString *girl5;
19 @property (nonatomic, copy) NSString *girl6;
20 @property (nonatomic, copy) NSString *girl7;
21 @property (nonatomic, copy) NSString *girl8;
22 @property (nonatomic, copy) NSString *girl9;
23 @property (nonatomic, copy) NSString *girl10;
24
25 @end
四、實現實體基類中的方法。
實體基類中的方法是從各個Model中抽象出來的並且可以重復利用的部分,在實體基類的方法中大致包括:生成getter方法,生成setter方法,獲取Model類的屬性,把字典的值賦給對應的Model, 動態的調用getter方法對實體類的屬性值進行遍歷。本篇博客中回給出一部分,剩下的一部分會在以後的博客中陸續給出。
1.根據Key值生成set方法
首先要編寫的方法是傳入一個字符串,然後返回該字符串所對應屬性的setter方法。這個方法其實很簡單的,就是把對應的字符串的首字母大寫並且拼接上set關鍵字,再生產SEL並返回,該方法的具體實現如下:
1 #pragma mark -- 通過字符串來創建該字符串的Setter方法,並返回
2 - (SEL) creatSetterWithPropertyName: (NSString *) propertyName{
3
4 //1.首字母大寫
5 propertyName = propertyName.capitalizedString;
6
7 //2.拼接上set關鍵字
8 propertyName = [NSString stringWithFormat:@"set%@:", propertyName];
9
10 //3.返回set方法
11 return NSSelectorFromString(propertyName);
12 }
2.把字典傳入到方法中,並把字典的值賦給相應實體類的屬性,該方法需要調用上述方法來生成setter方法,通過setter方法把字典的Value賦值給實體類對應的屬性,代碼如下,下面代碼中的注釋還是比較詳細的,具體細節就參考下面注釋的內容了。通過調用這個方法就可以把字典的值賦給對應的實體類的屬性,調用這個方法的前提是要求字典的key與實體類的屬性名必須相同。有的小伙伴會問如果不一樣該怎麼做呢?這個問題到下篇博客中在進行介紹。
1 /************************************************************************
2 *把字典賦值給當前實體類的屬性
3 *參數:字典
4 *適用情況:當網絡請求的數據的key與實體類的屬性相同時可以通過此方法吧字典的Value
5 * 賦值給實體類的屬性
6 ************************************************************************/
7
8 -(void) assginToPropertyWithDictionary: (NSDictionary *) data{
9
10 if (data == nil) {
11 return;
12 }
13
14 ///1.獲取字典的key
15 NSArray *dicKey = [data allKeys];
16
17 ///2.循環遍歷字典key, 並且動態生成實體類的setter方法,把字典的Value通過setter方法
18 ///賦值給實體類的屬性
19 for (int i = 0; i < dicKey.count; i ++) {
20
21 ///2.1 通過getSetterSelWithAttibuteName 方法來獲取實體類的set方法
22 SEL setSel = [self creatSetterWithPropertyName:dicKey[i]];
23
24 if ([self respondsToSelector:setSel]) {
25 ///2.2 獲取字典中key對應的value
26 NSString *value = [NSString stringWithFormat:@"%@", data[dicKey[i]]];
27
28 ///2.3 把值通過setter方法賦值給實體類的屬性
29 [self performSelectorOnMainThread:setSel
30 withObject:value
31 waitUntilDone:[NSThread isMainThread]];
32 }
33
34 }
35
36 }
3.接下來就是開始編寫實體類的入口了,也就是便利初始化方法和便利構造器。並在頭文件中留出接口,下面先給出便利初始化方法然後在給出便利構造器。
(1)下面的代碼是實體類的便利初始化方法,當然是實例方法,該方法需要傳入一個字典,這個字典中的key就是該實體類的屬性名,值就是要給該實體類的屬性賦的值。並且返回該實體類的實例,簡單的說就是調用-(void) assginToPropertyWithDictionary: (NSDictionary*) data方法,具體代碼如下:
1 - (instancetype)initWithDictionary: (NSDictionary *) data{
2 {
3 self = [super init];
4 if (self) {
5 [self assginToPropertyWithDictionary:data];
6 }
7 return self;
8 }
9 }
(2)下面將要給出便利構造器,當然便利構造器是類方法,並且返回該類的一個實例。用大白話說,便利構造器就是分配內存後調用便利初始化方法然後返回該對象的實例,下方是實體類對應的便利構造器:
1 + (instancetype)modelWithDictionary: (NSDictionary *) data{
2
3 return [[self alloc] initWithDictionary:data];
4
5 }
五、測試上面的代碼
上面運行這麼多了得運行一下代碼看一下結果吧。因為我們這是基於系統的控制台程序,所以我們需要在main函數中進行調用我們編寫的方法,需要把我們上面生成的測試字典傳入到實體類的構造器中,並且獲取實體類的一個實例。該獲取的實體類的實例中的屬性就已經被賦值上了傳入的字典的值。具體調用方法如下所示。
1 BeautifulGirlModel *beautifulGirl = [BeautifulGirlModel modelWithDictionary:data];
2
3 NSLog(@"%@", beautifulGirl.girl0);
運行結果如下:
使用setValuesForKeysWithDictionary方法賦值,測試代碼如下:
BeautifulGirlModel *beautifulGirl = [[BeautifulGirlModel alloc] init];
[beautifulGirl setValuesForKeysWithDictionary:data];
最後給出最笨的賦值方法,也是最容易學會的賦值方法,不過這種方式維護起來回不太方便,而且大部分做的都是體力活的,實例如下:
1 BeautifulGirlModel *beautifulGirl1 = [[BeautifulGirlModel alloc] init];
2 beautifulGirl1.girl0 = data[@"girl0"];
3 beautifulGirl1.girl1 = data[@"girl1"];
4 beautifulGirl1.girl2 = data[@"girl2"];
5 beautifulGirl1.girl3 = data[@"girl3"];
6 beautifulGirl1.girl4 = data[@"girl4"];
7 beautifulGirl1.girl5 = data[@"girl5"];
8 beautifulGirl1.girl6 = data[@"girl6"];
9 beautifulGirl1.girl7 = data[@"girl7"];