iOS開發UI篇—從代碼的逐步優化看MVC數組
1、要求mvc
要求完成下面一個小的應用程序。app
2、一步步對代碼進行優化ide
注意:在開發過程當中,優化的過程是一步一步進行的。(若是一我的要吃五個包子才能吃飽,那麼他是否直接吃第五個,前面四個不用吃就飽了?)優化
1.完成基本要求的代碼(使用了字典轉模型和xib連線)atom
(1)文件結構spa
(2)主要代碼3d
字典轉模型部分:code
YYappInfo.h頭文件orm
1 // 2 // YYappInfo.h 3 // 12-視圖改進(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 11 @interface YYappInfo : NSObject 12 @property(nonatomic,copy)NSString *name; 13 @property(nonatomic,copy)NSString *icon; 14 @property(nonatomic,strong,readonly)UIImage *img; 15 16 -(instancetype)initWithDict:(NSDictionary *)dict; 17 /**工廠方法*/ 18 +(instancetype)appInfoWithDict:(NSDictionary *)dict; 19 @end
YYappInfo.m文件
1 // 2 // YYappInfo.m 3 // 12-視圖改進(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYappInfo.h" 10 @interface YYappInfo() 11 { 12 UIImage *_img; 13 } 14 @end 15 @implementation YYappInfo 16 -(instancetype)initWithDict:(NSDictionary *)dict 17 { 18 if (self=[super init]) { 19 self.name=dict[@"name"]; 20 self.icon=dict[@"icon"]; 21 } 22 return self; 23 } 24 25 +(instancetype)appInfoWithDict:(NSDictionary *)dict 26 { 27 return [[self alloc]initWithDict:dict]; 28 } 29 30 -(UIImage *)img 31 { 32 _img=[UIImage imageNamed:self.icon]; 33 return _img; 34 } 35 @end
xib部分(YYappInfoView.h文件):
注:(xib視圖和YYappInfoView進行了關聯,三個屬性均進行了連線)
1 // 2 // YYappInfoView.h 3 // 12-視圖改進(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 11 @interface YYappInfoView : UIView 12 @property (strong, nonatomic) IBOutlet UIImageView *appInfoViewimg; 13 14 @property (strong ,nonatomic) IBOutlet UILabel *appInfoViewlab; 15 @property (strong, nonatomic) IBOutlet UIButton *appInfoViewbtn; 16 17 @end
主要功能實現部分:
YYViewController.m文件
1 // 2 // YYViewController.m 3 // 12-視圖改進(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYViewController.h" 10 #import "YYappInfo.h" 11 #import "YYappInfoView.h" 12 13 @interface YYViewController () 14 @property(nonatomic,strong)NSArray *apps; 15 @end 16 17 //開發思路 18 //1.加載plist文件(字典轉模型提供接口) 19 //2.使用xib文件完成單個的view 20 //3.計算座標,使用for循環把view展示到界面上 21 //4.優化代碼 22 @implementation YYViewController 23 24 //get方法,懶加載 25 -(NSArray *)apps 26 { 27 if (!_apps) { 28 NSString *path = [[NSBundle mainBundle]pathForResource:@"app.plist" ofType:nil]; 29 NSArray * arrayM = [NSArray arrayWithContentsOfFile:path]; 30 31 NSMutableArray *appinfoarray=[NSMutableArray array]; 32 for (NSDictionary *dict in arrayM) { 33 [appinfoarray addObject:[YYappInfo appInfoWithDict:dict]]; 34 } 35 _apps = appinfoarray; 36 } 37 return _apps; 38 } 39 40 - (void)viewDidLoad 41 { 42 [super viewDidLoad]; 43 NSLog(@"%d",self.apps.count); 44 45 int totalloc = 3; 46 CGFloat appviewW = 80; 47 CGFloat appviewH = 90; 48 CGFloat margin = (self.view.frame.size.width-totalloc*appviewW)/(totalloc+1); 49 50 int count=self.apps.count; 51 for (int i = 0; i < count; i++) { 52 int row = i/totalloc; 53 int loc = i%totalloc; 54 55 CGFloat appviewX = margin + (margin + appviewW) * loc; 56 CGFloat appviewY = margin + (margin + appviewH) * row; 57 58 YYappInfo *appinfo=self.apps[i]; 59 60 //拿出xib中的數據 61 NSArray *arryM=[[NSBundle mainBundle]loadNibNamed:@"appInfoxib" owner:nil options:nil]; 62 YYappInfoView *appinfoview=[arryM firstObject]; 63 //設置位置 64 appinfoview.frame=CGRectMake(appviewX, appviewY, appviewW, appviewH); 65 //設置值 66 appinfoview.appInfoViewimg.image=appinfo.img; 67 appinfoview.appInfoViewlab.text=appinfo.name; 68 //添加到視圖 69 appinfoview.appInfoViewbtn.tag=i; 70 [appinfoview.appInfoViewbtn addTarget:self action:@selector(Click:) forControlEvents:UIControlEventTouchUpInside]; 71 [self.view addSubview:appinfoview]; 72 } 73 } 74 -(void)Click:(UIButton *)btn 75 { 76 btn.enabled=NO; 77 YYappInfo *appinfo=self.apps[btn.tag]; 78 UILabel *lab=[[UILabel alloc]initWithFrame:CGRectMake(60, 450, 200, 20)]; 79 [lab setBackgroundColor:[UIColor lightGrayColor]]; 80 [lab setTextAlignment:NSTextAlignmentCenter]; 81 [lab setText:[NSString stringWithFormat:@"%@成功下載",appinfo.name]]; 82 [self.view addSubview:lab]; 83 84 lab.alpha=1.0; 85 [UIView animateWithDuration:2.0 animations:^{ 86 lab.alpha=0; 87 }completion:^(BOOL finished) { 88 [lab removeFromSuperview]; 89 }]; 90 } 91 @end
2.對1進行優化(把數據呈現部分封裝到視圖)
說明:在1的基礎上尋找還會有那些能夠優化的部分
1)改進思路:
(1)1中主文件的66~67行對控件屬性的設置可否拿到視圖中進行?
(2)1中61~62行是從xib文件中讀取信息的操做,且和主控制器沒有什麼太大的關聯,可否把它也封裝到視圖中進行?
(3)當上述兩個步驟完成後,主文件69行之後的按鈕操做和按鈕單擊事件就顯得很突兀,放在主控制器中已經再也不合適,是否能夠把它放到視圖中進行處理
2)按照上述思路優化後的代碼以下:
優化視圖,在視圖部分之對外提供一個接口,把數據的處理封裝在內部
YYappInfoView.h文件代碼:
1 // 2 // YYappInfoView.h 3 // 12-視圖改進(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 @class YYappInfo; 11 @interface YYappInfoView : UIView 12 13 //讀取 14 //+(instancetype)appInfoView; 15 //只對外開放一個數據接口 16 +(instancetype)appInfoViewWithappInfo:(YYappInfo *)appinfo; 17 @end
YYappInfoView.m文件代碼
說明:該文件中的屬性和click等均已作了連線的操做。
1 // 2 // YYappInfoView.m 3 // 12-視圖改進(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYappInfoView.h" 10 #import "YYappInfo.h" 11 //私有擴展,把屬性拿進來 12 @interface YYappInfoView () 13 @property (strong, nonatomic) IBOutlet UIImageView *appInfoViewimg; 14 @property (strong ,nonatomic) IBOutlet UILabel *appInfoViewlab; 15 @property (strong, nonatomic) IBOutlet UIButton *appInfoViewbtn; 16 @property(strong,nonatomic)YYappInfo *appinfo; 17 18 @end 19 @implementation YYappInfoView 20 21 +(instancetype)appInfoView 22 { 23 NSArray *arryM=[[NSBundle mainBundle]loadNibNamed:@"appInfoxib" owner:nil options:nil]; 24 YYappInfoView *appinfoview=[arryM firstObject]; 25 return appinfoview; 26 } 27 28 +(instancetype)appInfoViewWithappInfo:(YYappInfo *)appinfo 29 { 30 YYappInfoView *appInfoView=[self appInfoView]; 31 appInfoView.appinfo=appinfo; 32 return appInfoView; 33 } 34 35 -(void)setAppinfo:(YYappInfo *)appinfoc 36 { 37 //這裏必定要記錄變化 38 _appinfo=appinfoc; 39 self.appInfoViewimg.image=appinfoc.img;
self.appInfoViewlab.text=appinfoc.name;
41 }
42 - (IBAction)Click { 43 44 self.appInfoViewbtn.enabled=NO; 45 //YYappInfo *appinfo=self.apps[]; 46 47 YYappInfo *appinfo=self.appinfo; 48 UILabel *lab=[[UILabel alloc]initWithFrame:CGRectMake(60, 450, 200, 20)]; 49 [lab setBackgroundColor:[UIColor lightGrayColor]]; 50 [lab setTextAlignment:NSTextAlignmentCenter]; 51 [lab setText:[NSString stringWithFormat:@"%@成功下載",appinfo.name]]; 52 //把lab添加到父視圖(即view中) 53 [self.superview addSubview:lab]; 54 55 lab.alpha=1.0; 56 [UIView animateWithDuration:2.0 animations:^{ 57 lab.alpha=0; 58 }completion:^(BOOL finished) { 59 [lab removeFromSuperview]; 60 }]; 61 } 62 63 64 @end
優化後的主控制器部分
YYViewController.m文件代碼
1 // 2 // YYViewController.m 3 // 12-視圖改進(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYViewController.h" 10 #import "YYappInfo.h" 11 #import "YYappInfoView.h" 12 13 @interface YYViewController () 14 @property(nonatomic,strong)NSArray *apps; 15 @end 16 @implementation YYViewController 17 18 -(NSArray *)apps 19 { 20 if (!_apps) { 21 NSString *path = [[NSBundle mainBundle]pathForResource:@"app.plist" ofType:nil]; 22 NSArray * arrayM = [NSArray arrayWithContentsOfFile:path]; 23 24 NSMutableArray *appinfoarray=[NSMutableArray array]; 25 for (NSDictionary *dict in arrayM) { 26 [appinfoarray addObject:[YYappInfo appInfoWithDict:dict]]; 27 } 28 _apps = appinfoarray; 29 } 30 return _apps; 31 } 32 33 - (void)viewDidLoad 34 { 35 [super viewDidLoad]; 36 NSLog(@"%d",self.apps.count); 37 38 int totalloc = 3; 39 CGFloat appviewW = 80; 40 CGFloat appviewH = 90; 41 CGFloat margin = (self.view.frame.size.width-totalloc*appviewW)/(totalloc+1); 42 43 int count=self.apps.count; 44 for (int i = 0; i < count; i++) { 45 int row = i/totalloc; 46 int loc = i%totalloc; 47 48 CGFloat appviewX = margin + (margin + appviewW) * loc; 49 CGFloat appviewY = margin + (margin + appviewH) * row; 50 51 /*思路: 52 要達到的效果 appinfoview.appinfo=appinfo; 53 優化後即變成 appinfoview.appinfo=self.apps[i]; 54 要進行上面代碼的操做,須要在視圖中新增長一個appinfo類的屬性,這樣數據——》視圖的轉換便可以不須要在主控制器中完成,讓程序結構一目瞭然 55 */ 56 YYappInfo *appinfo=self.apps[i]; 57 YYappInfoView *appinfoview=[YYappInfoView appInfoViewWithappInfo:appinfo]; 58 //設置位置 59 appinfoview.frame=CGRectMake(appviewX, appviewY, appviewW, appviewH); 60 //添加 61 [self.view addSubview:appinfoview]; 62 } 63 } 64 @end
3.對2進一步優化(把數據處理部分拿到模型中去進行)
(1)思路:把字典轉模型部分的數據處理操做,拿到模型中去處理,這樣外界不須要再關心數據處理的內部細節。
(2)優化後的代碼以下
YYappInfo.h文件中向外開放一個接口,返回一個處理好的數組。
1 // 2 // YYappInfo.h 3 // 12-視圖改進(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 11 @interface YYappInfo : NSObject 12 @property(nonatomic,copy)NSString *name; 13 @property(nonatomic,copy)NSString *icon; 14 @property(nonatomic,strong)UIImage *img; 15 16 -(instancetype)initWithDict:(NSDictionary *)dict; 17 /**工廠方法*/ 18 +(instancetype)appInfoWithDict:(NSDictionary *)dict; 19 +(NSArray *)appinfoarray; 20 @end
YYappInfo.m文件中的數據處理
1 // 2 // YYappInfo.m 3 // 12-視圖改進(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYappInfo.h" 10 @interface YYappInfo() 11 @end 12 @implementation YYappInfo 13 -(instancetype)initWithDict:(NSDictionary *)dict 14 { 15 if (self=[super init]) { 16 self.name=dict[@"name"]; 17 self.icon=dict[@"icon"]; 18 } 19 return self; 20 } 21 22 +(instancetype)appInfoWithDict:(NSDictionary *)dict 23 { 24 return [[self alloc]initWithDict:dict]; 25 } 26 27 -(UIImage *)img 28 { 29 _img=[UIImage imageNamed:self.icon]; 30 return _img; 31 } 32 33 //把數據處理部分拿到模型中來處理 34 +(NSArray *)appinfoarray 35 { 36 NSString *path = [[NSBundle mainBundle]pathForResource:@"app.plist" ofType:nil]; 37 NSArray * arrayM = [NSArray arrayWithContentsOfFile:path]; 38 39 NSMutableArray *appinfoarray=[NSMutableArray array]; 40 for (NSDictionary *dict in arrayM) { 41 [appinfoarray addObject:[YYappInfo appInfoWithDict:dict]]; 42 } 43 return appinfoarray; 44 } 45 @end
主控制器中再也不須要關心數據處理的內部細節
YYViewController.m文件如今只是負責模型和視圖之間的協調工做了,怎麼樣?差很少了吧。
1 // 2 // YYViewController.m 3 // 12-視圖改進(1) 4 // 5 // Created by apple on 14-5-25. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYViewController.h" 10 #import "YYappInfo.h" 11 #import "YYappInfoView.h" 12 13 @interface YYViewController () 14 @property(nonatomic,strong)NSArray *apps; 15 @end 16 @implementation YYViewController 17 18 -(NSArray *)apps 19 { 20 if (!_apps) { 21 _apps=[YYappInfo appinfoarray]; 22 } 23 return _apps; 24 } 25 26 - (void)viewDidLoad 27 { 28 [super viewDidLoad]; 29 30 int totalloc = 3; 31 CGFloat appviewW = 80; 32 CGFloat appviewH = 90; 33 CGFloat margin = (self.view.frame.size.width-totalloc*appviewW)/(totalloc+1); 34 35 int count=self.apps.count; 36 for (int i = 0; i < count; i++) { 37 38 int row = i/totalloc; 39 int loc = i%totalloc; 40 41 CGFloat appviewX = margin + (margin + appviewW) * loc; 42 CGFloat appviewY = margin + (margin + appviewH) * row; 43 44 YYappInfo *appinfo=self.apps[i]; 45 YYappInfoView *appinfoview=[YYappInfoView appInfoViewWithappInfo:appinfo]; 46 appinfoview.frame=CGRectMake(appviewX, appviewY, appviewW, appviewH); 47 [self.view addSubview:appinfoview]; 48 } 49 } 50 @end
實現效果:
4.補充說明
View的封裝思路
(1) 若是一個view內部的子控件比較多,通常會考慮自定義一個view,把它內部子控件的建立屏蔽起來,不讓外界關心
(2) 外界能夠傳入對應的模型數據給view,view拿到模型數據後給內部的子控件設置對應的數據
3、mvc機制簡單說明
說明:
(1)在開發過程當中,做爲控制器處理的量級應該很輕,不應操心的不操心。協調好模型和視圖就ok了,要學會當一個好老闆。
(2)三個部分各司其職,數據模型只負責數據的處理,視圖部分只負責把拿到的數據進行顯示,兩個部分都是被動的,等待着大管家控制器的調遣。
(3)在OC中,若是視圖和數據模型之間有通道,那控制器是否處於失控狀態呢?