本篇文章,通過字典轉模型來改進上篇文章中的代碼.
字典轉模型,之前的文章已經介紹過,這里再重復一下:
字典轉模型
字典:用來存儲數據的,用鍵值對存儲數據,是一個nsdictionary ,(不好處:key值容易寫錯)
模型: 用來存儲數據的,一個字典對應一個模型,模型用屬性來存儲數據,是一個純潔的object對象
@PRoperty(nonatomic,copy)NSString *name;
@property(nonatomic,copy)NSString *icon;
字典轉模型:一個字典對應一個模型,把鍵值對轉化模型的屬性,就是把鍵值對的value賦值給模型的屬性
appModel.name = dict[@"name"];
appModel.icon = dict[@"icon"];
屬性的類型和名稱:屬性的類型和鍵值對的key值的類型是一樣,最好名稱也和key值的名稱一樣
* 字典缺陷:
0> 寫代碼的時候字典的鍵沒有智能提示, 但是模型的屬性可以有智能提示
1> "鍵"是字符串, 如果寫錯了, 編譯器不報錯(在編譯的時候不報錯), 運行時可能出錯, 出錯了很難找錯。
* 把字典轉模型的過程封裝到"模型"內部
* 原因: 將來的這個"模型"可能會在很多地方被用到(比如有很多個控制器都會使用這個模型), 那么每次用到模型的地方都需要寫一次把字典中的數據賦給模型屬性的代碼, 此時如果把 這些賦值語句封裝到模型內部, 會大大簡化了使用復雜度與代碼量。
*實現思路:
1> 在模型中接收一個NSDictionary的參數, 然后在模型內部把NSDictioanry中的鍵值對數據賦值給模型的屬性。
2> 封裝一個initWithDict方法和一個appWithDict方法(規范)
- (instancetype)initWithDict:(NSDictionary *)dict{}
+(instancetype)appModelWithDict:(NSDictionary *)dict{}
應用代碼結構及plist截圖;

下面附上源代碼:
KZAppModel.h
1 // 2 // KZAppModel.h 3 // UI基礎-03-05-14 4 // 5 // Created by hukezhu on 15/5/15. 6 // 7 // 8 9 #import <Foundation/Foundation.h>10 11 @interface KZAppModel : NSObject12 /**13 * 應用圖標14 */15 @property (nonatomic ,copy) NSString *icon;16 /**17 * 應用名稱18 */19 @property (nonatomic ,copy) NSString *name;20 21 /**22 * 通過字典來初始化對象23 *24 * @param dict 字典對象25 *26 * @return 已經初始化完畢的模型對象27 */28 - (instancetype)initWithDict:(NSDictionary *)dict;29 30 //類方法31 + (instancetype)appWithModelDict:(NSDictionary *)dict;32 33 @end
KZAppModel.m
1 // 2 // KZAppModel.m 3 // UI基礎-03-05-14 4 // 5 // Created by hukezhu on 15/5/15. 6 // 7 // 8 9 #import "KZAppModel.h"10 11 @implementation KZAppModel12 //對象方法13 -(instancetype)initWithDict:(NSDictionary *)dict{14 15 //重寫構造方法的默認寫法16 if(self = [super init]){17 18 //將字典的所有屬性賦值給模型19 self.icon = dict[@"icon"];20 self.name = dict[@"name"];21 }22 return self;23 }24 //類方法25 +(instancetype)appWithModelDict:(NSDictionary *)dict{26 27 //注意此處是self28 return [[self alloc]initWithDict:dict];29 }30 @end
ViewController.m:
1 // 2 // ViewController.m 3 // 03-應用管理 4 // 5 // Created by hukezhu on 15/5/14. 6 // 7 // 8 9 #import "ViewController.h" 10 #import "KZAppModel.h" 11 12 @interface ViewController () 13 @property (nonatomic,strong)NSArray *apps; 14 @end 15 16 @implementation ViewController 17 18 - (void)viewDidLoad { 19 [super viewDidLoad]; 20 21 //每一行的應用的個數 22 int totalCol = 3; 23 24 25 //添加一個小的view 26 CGFloat appW = 80; 27 CGFloat appH = 100; 28 CGFloat marginX = 20; 29 CGFloat marginY = 20; 30 CGFloat hightMargin = 30; 31 CGFloat leftMargin = (self.view.frame.size.width - totalCol * appW - (totalCol - 1) *marginX)* 0.5; 32 33 34 35 for (int i = 0; i < self.apps.count; i++) { 36 37 38 //計算行號和列號 39 int row = i / totalCol; 40 int col = i % totalCol; 41 42 CGFloat appX = leftMargin + (marginX + appW)* col; 43 CGFloat appY = hightMargin + (marginY + appH)* row; 44 45 //1.添加view 46 47 //1.1新建一個UIView 48 UIView *appView = [[UIView alloc]init]; 49 //1.2設置frame 50 appView.frame = CGRectMake(appX, appY, appW, appH); 51 //1.3設置背景色(便于代碼階段驗證,之后會刪除) 52 //appView.backgroundColor = [UIColor redColor]; 53 //1.4將這個appView添加到view中 54 [self.view addSubview:appView]; 55 56 //加載數據 57 //NSDictionary *dict = self.apps[i]; 58 //將數據賦值給模型對象 59 KZAppModel *appModel = self.apps[i]; 60 61 //2.添加圖片UIImageView 62 CGFloat imageW = 60; 63 CGFloat imageH = 50; 64 CGFloat imageX = (appW - imageW)*0.5; 65 CGFloat imageY = 0; 66 UIImageView *imageView = [[UIImageView alloc]init]; 67 imageView.frame = CGRectMake(imageX, imageY, imageW, imageH); 68 //imageView.backgroundColor = [UIColor blueColor]; 69 //imageView.image = [UIImage imageNamed:dict[@"icon"]]; 70 //從模型對象中取出數據 71 imageView.image = [UIImage imageNamed:appModel.icon]; 72 [appView addSubview:imageView]; 73 74 75 //3.添加應用名稱 76 77 CGFloat labelW = 80; 78 CGFloat labelH = 25; 79 CGFloat labelX = 0; 80 CGFloat labelY = imageH; 81 UILabel *label = [[UILabel alloc]init]; 82 label.frame = CGRectMake(labelX, labelY, labelW, labelH); 83 //label.backgroundColor = [UIColor grayColor]; 84 //label.text = dict[@"name"]; 85 //從模型對象中取出數據name 86 label.text = appModel.name; 87 88 //設置字體大小 89 label.font = [UIFont systemFontOfSize:13]; 90 //設置字體居中 91 label.textAlignment = NSTextAlignmentCenter; 92 [appView addSubview:label]; 93 94 //4.添加下載按鈕 95 96 CGFloat downloadW = 60; 97 CGFloat downloadH = 25; 98 CGFloat downloadX = 10; 99 CGFloat downloadY = labelH + labelY;100 UIButton *downloadBtn = [[UIButton alloc]init];101 downloadBtn.frame = CGRectMake(downloadX, downloadY, downloadW, downloadH);102 //downloadBtn.backgroundColor = [UIColor yellowColor];103 //設置背景圖片104 [downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen"] forState:UIControlStateNormal];105 [downloadBtn setBackgroundImage:[UIImage imageNamed:@"buttongreen_highlighted"] forState:UIControlStateHighlighted];106 //設置字體第一種方法107 [downloadBtn setTitle:@"下載" forState:UIControlStateNormal];108 109 //設置字體第二種方法(不推薦使用)110 downloadBtn.titleLabel.text = @"下載";111 112 //設置字體大小113 downloadBtn.titleLabel.font = [UIFont systemFontOfSize:15];114 [appView addSubview:downloadBtn];115 116 117 [downloadBtn addTarget:self action:@selector(btnOnClick:) forControlEvents:UIControlEventTouchUpInside];118 }119 120 121 122 123 124 }125 /**126 * 按鈕的點擊方法127 *128 * @param btn 將按鈕本身傳入方法中,哪個按鈕被點擊就調用這個方法129 */130 - (void)btnOnClick:(UIButton *)btn{131 132 //NSLog(@"------%@",btn);133 btn.enabled = NO;134 [btn setTitle:@"已下載" forState:UIControlStateNormal];135 136 CGFloat labelW = 120;137 CGFloat labelH = 30;138 CGFloat labelX = (self.view.frame.size.width - labelW)* 0.5;139 CGFloat labelY = (self.view.frame.size.height - labelH)*0.5;140 UILabel *label = [[UILabel alloc]init];141 label.frame = CGRectMake(labelX, labelY, labelW, labelH);142 label.text = @"正在下載";143 //設置字體顏色144 label.textColor = [UIColor redColor];145 //設置字體居中146 label.textAlignment = NSTextAlignmentCenter;147 //設置 背景色148 label.backgroundColor = [UIColor blackColor];149 150 //設置圓角的半徑151 label.layer.cornerRadius = 8;152 //將多余的部分減掉153 label.layer.masksToBounds = YES;154 //設置透明度155 label.alpha = 0.0;156 //將label添加到view中157 [self.view addSubview:label];158 //使用block動畫,動畫持續時間2秒159 [UIView animateWithDuration:2.0 animations:^{160 label.alpha = 0.5;161 } completion:^(BOOL finished) {162 if (finished) {163 [UIView animateWithDuration:2.0 delay:0.1 options:UIViewAnimationOptionCurveLinear animations:^{164 label.alpha = 0.0;165 } completion:^(BOOL finished) {166 //上面將透明度設置為0,界面上已經不顯示這個label,但是它仍然在內存中,所以為了節約內存,仍要將其從內存中刪除167 [label removeFromSuperview];168 169 }];170 }171 }];172 173 }174 /**175 * "懶加載",加載應用數據176 *177 */178 - (NSArray *)apps{179 180 //如果_apps為空,才加載數據181 if (_apps == nil) {182 //獲取plist的全路徑183 NSString *path = [[NSBundle mainBundle]pathForResource:@"app.plist" ofType:nil];184 185 //加載數組186 NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];187 188 //創建一個可變數組,來動態接收模型對象189 NSMutableArray *array = [NSMutableArray array];190 191 //通過循環,將字典數組的字典取出,轉成模型對象192 for (NSDictionary *dict in dictArray) {193 KZAppModel *appModel = [KZAppModel appWithModelDict:dict];194 [array addObject:appModel];195 }196 _apps = array;197 }198 return _apps;199 }200 201 - (void)didReceiveMemoryWarning {202 [super didReceiveMemoryWarning];203 // Dispose of any resources that can be recreated.204 }205 206 @end
1.字典轉模型
文章開頭,以及前面的文章介紹了好多次了,這里不再贅述.
2.在模型類中,聲明和實現方法的時候,定義的返回值類型為instancetype,這個與id的區別:
1. 使用id作為方法返回值的問題:
在接收方法的返回值的時候可以使用任何類型來接收, 編譯都不報錯, 但是運行時可能出錯。
2. instancetype需要注意的點
1> instancetype在類型表示上, 與id意思一樣, 都表示任何對象類型
2> instancetype只能用作返回值類型, 不能向id一樣聲明變量、用作參數等
3> 使用instancetype, 編譯器會檢測instancetype的真實類型, 如果類型不匹配, 編譯時就發出警告。(instancetype出現在哪個類型中就表示對應的類型)
這里我們還是使用了代碼來創建的空間,蘋果提供了xib,用來描述局部界面的文件(相對于storyboard的描述全局文件來說),使用Xib我們可以通過拖拽的方法來進行可視化開發,比較方便,下篇文章,將使用xib來改進這個代碼.
|
新聞熱點
疑難解答