iOS开发UI篇—从代码的逐步优化看MVC
一、要求
要求完成下面一个小的应用程序。
二、一步步对代码进行优化
注意:在开发过程中,优化的过程是一步一步进行的。(如果一个人要吃五个包子才能吃饱,那么他是否直接吃第五个,前面四个不用吃就饱了?)
1.完成基本要求的代码(使用了字典转模型和xib连线)
(1)文件结构
(2)主要代码
字典转模型部分:
TXApp.h头文件
1 // 屌丝逆天-应用管理01 2 // 3 // Created by 鑫 on 14-10-4. 4 // Copyright (c) 2014年 梁镋鑫. All rights reserved. 5 // 6 7 #import <Foundation/Foundation.h> 8 9 @interface TXApp : NSObject 10 /** 11 * 图标的名称 12 */ 13 @property(nonatomic,copy)NSString *name; 14 /** 15 * 图标 16 */ 17 @property(nonatomic,copy)NSString *icon; 18 /** 19 * 通过字典初始化模型对象 20 * 21 * @param dict 字典对象 22 * 23 * @return 一初始化完毕的模型对象 24 */ 25 -(instancetype)initWithDict:(NSDictionary *)dict; 26 +(instancetype)appWithDict:(NSDictionary *) dict; 27 @end
TXApp.m文件
1 // TXApp.m 2 // 屌丝逆天-应用管理01 3 // 4 // Created by 鑫 on 14-10-4. 5 // Copyright (c) 2014年 梁镋鑫. All rights reserved. 6 // 7 8 #import "TXApp.h" 9 10 @implementation TXApp 11 -(instancetype)initWithDict:(NSDictionary *)dict 12 { 13 if (self = [super init]) { 14 self.name = dict[@"name"]; 15 self.icon = dict[@"icon"]; 16 } 17 return self; 18 } 19 +(instancetype)appWithDict:(NSDictionary *)dict 20 { 21 return [[self alloc]initWithDict:dict]; 22 } 23 @end
xib部分(TXAppView.h文件):
注:(xib视图和TXAppView.m进行了关联,三个属性均进行了连线)
1 #import <UIKit/UIKit.h> 2 @class TXApp; 3 @interface TXAppView : UIView 4 @property (weak, nonatomic) IBOutlet UIImageView *iconView; 5 @property (weak, nonatomic) IBOutlet UILabel *namelable; 6 /** 7 * 模型 8 */ 9 @property(nonatomic ,strong)TXApp *app; 10 /** 11 * 通过模型数据来创建一个view 12 */ 13 +(instancetype)appViewWithApp:(TXApp *)app; 14 @end
主要功能实现部分:
TXViewController.m文
1 #import "TXViewController.h" 2 #import "TXApp.h" 3 #import "TXAppView.h" 4 @interface TXViewController () 5 /** 6 * 传放应用信息 7 */ 8 @property(nonatomic ,strong)NSArray *apps; 9 10 11 @end 12 13 @implementation TXViewController 14 15 - (void)viewDidLoad 16 { 17 [super viewDidLoad]; 18 19 //添加应用信息 20 21 //总列数(一行最多3列) 22 int totalColumns = 3; 23 24 //应用尺寸 25 CGFloat appW = 85; 26 CGFloat appH = 90; 27 28 //间隙 = (控制器view的宽度-3* 应用宽度)/4 29 CGFloat marginX = (self.view.frame.size.width - totalColumns * appW) / (totalColumns + 1); 30 CGFloat marginY = 15; 31 32 //根据应用个数创建对用框框 33 34 for (int index = 0; index < self.apps.count; index++) { 35 //3.1.创建view 36 NSBundle *bundle = [NSBundle mainBundle]; 37 //读取xib文件(会创建xib中的描述的所有对象,并且安顺序放到数组中返回; 38 NSArray * objs = [bundle loadNibNamed:@"TXAppView" owner:nil options:nil]; 39 TXAppView *appView = [objs lastObject]; 40 41 //3.2添加view 42 [self.view addSubview:appView]; 43 44 //// 3.3.设置frame 45 int row = index / totalColumns; 46 int col = index % totalColumns; 47 // 计算x和y 48 CGFloat appX = marginX + col * (appW + marginX); 49 CGFloat appY = 30 + row * (appH + marginY); 50 appView.frame = CGRectMake(appX, appY, appW, appH); 51 52 //3.4设置数据 53 TXApp *app = self.apps[index]; 54 55 //3.4.1设置图标 56 appView.iconView.image = [UIImage imageNamed:app.icon]; 57 //3.4.2设置名称 58 appView.namelable.text = app.name; 59 //设置数据放到view里面进行 60 61 } 62 63 64 } 65 -(NSArray *)apps 66 { 67 if (_apps ==nil) { 68 //初始化 69 70 //1.获取plist的全路径 71 NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil]; 72 73 //2.加载数组 74 NSArray *dictArray = [NSArray arrayWithContentsOfFile:path]; 75 //将dictArray里面所有的字典转成模型对象,方到新的数组中 76 NSMutableArray * appArray = [NSMutableArray array]; 77 for (NSDictionary *dict in dictArray) { 78 //创建模型对象 79 TXApp *app = [TXApp appWithDict:dict]; 80 81 //把模型对象放到数组中 82 83 [appArray addObject:app]; 84 85 86 87 } 88 _apps = appArray; 89 90 } 91 return _apps; 92 } 93 94 95 - (void)didReceiveMemoryWarning 96 { 97 [super didReceiveMemoryWarning]; 98 // Dispose of any resources that can be recreated. 99 }
2.对1进行优化(把数据呈现部分封装到视图)
说明:在1的基础上寻找还会有那些可以优化的部分
1)改进思路:
(1)1中主文件的66~67行对控件属性的设置能否拿到视图中进行?
(2)1中61~62行是从xib文件中读取信息的操作,且和主控制器没有什么太大的关联,能否把它也封装到视图中进行?
(3)当上述两个步骤完成后,主文件69行以后的按钮操作和按钮单击事件就显得很突兀,放在主控制器中已经不再合适,是否可以把它放到视图中进行处理
2)按照上述思路优化后的代码如下:
优化视图,在视图部分之对外提供一个接口,把数据的处理封装在内部
3.对2进一步优化(把数据处理部分拿到模型中去进行)
(1)思路:把字典转模型部分的数据处理操作,拿到模型中去处理,这样外界不需要再关心数据处理的内部细节。
(2)优化后的代码如下
TXAppView.m文件中的数据处理
1 #import "TXAppView.h" 2 #import "TXApp.h" 3 @implementation TXAppView 4 5 - (id)initWithFrame:(CGRect)frame 6 { 7 self = [super initWithFrame:frame]; 8 if (self) { 9 // Initialization code 10 } 11 return self; 12 } 13 14 +(instancetype)appViewWithApp:(TXApp *)app 15 { 16 NSBundle *bundle = [NSBundle mainBundle]; 17 //读取xib文件(会创建xib中描述的所有对象,并且安顺序放到数组中 18 NSArray *objs= [bundle loadNibNamed:@"TXAppView" owner:nil 19 options:nil]; 20 TXAppView * appView = [objs lastObject]; 21 appView.app =app; 22 return appView; 23 } 24 /** 25 * 从写set方法,设计内部控件的数据 26 * 27 * @param 用传如的模型设置数据 28 */ 29 -(void)setApp:(TXApp *)app 30 { 31 _app = app; 32 //1.设置图标 33 self.iconView.image = [UIImage imageNamed:app.icon]; 34 // 2.设置名称 35 self.namelable.text = app.name; 36 } 37 @end
4.补充说明
View的封装思路
(1) 如果一个view内部的子控件比较多,一般会考虑自定义一个view,把它内部子控件的创建屏蔽起来,不让外界关心
(2) 外界可以传入对应的模型数据给view,view拿到模型数据后给内部的子控件设置对应的数据
三、mvc机制简单说明
说明:
(1)在开发过程中,作为控制器处理的量级应该很轻,不该操心的不操心。协调好模型和视图就ok了,要学会当一个好老板。
(2)三个部分各司其职,数据模型只负责数据的处理,视图部分只负责把拿到的数据进行显示,两个部分都是被动的,等待着大管家控制器的调遣。
(3)在OC中,如果视图和数据模型之间有通道,那控制器是否处于失控状态呢?