IOS之MVC。。。

MVC模式是软件工程中的一种软件架构模式。
把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。

  • Model: 程序的数据部分,用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法
  • View: 程序的界面展示,实际上是数据有目的的界面显示,但视图绝不与model直接交互,在视图中一般没有程序上的逻辑;
  • Controller: 将Model与View连接起来协同工作的部分,控制器起到不同层面间的组织作用,用于控制应用程序的流程。

优点MVC使得程序的输入、处理和输出强制性的分开,这增加了软件的扩展性、维护性以及封装性,使得软件开发从不同层面上分离解耦。直接描述这些优点可能看着会很晦涩,举几个例子来说明一下:1.几个界面可以共用一个model,这使得model可复用,同时只有model的一个拷贝使得代码更易于维护;2.当模型,数据与控制器是相分离的时候,改变业务规则就变得很容易,数据的存储可以随意的迁移,因为模型对控制器的接口是不变的,这样界面仍然可以正确的展示,界面UI也是可以任意改变,因为它只关心界面不会影响到其他;3.MVC这样将三方独立的区分开,也绝对的有利于多人或者团队开发。

缺点虽然MVC有着那么多优点,并且我们的项目也采用这样的开发模式,但是他的缺点也很明显,严格的三者分离有时候是很难区分的,需要仔细的思考确定边界,同时Model与View不能直接交互,就必然在性能上有一些损失(极小)。


 了解了MVC的基本概念及思路后,我们来说说MVC在IOS开发当中的体现及实际应用。首先来看一下斯坦福公开课给出的图:

 先解释图中类似三叉路口的白线与黄线,M与V之间是两条黄线,这可以理解为两条黄色禁线,禁止了model与view的直接通信,所以说model与view是不能直接交互的,任何方向都不行;而C到M与C到V之间是一条虚线与一条实现,靠近C的是虚线,靠近M与V的为实线,可以理解为C到M或者V是可以穿越的,可以直接调用,而白色的实线则代表着你可以穿越它,可以去调用,但是得通过某种特殊方式,非直接调用,如何调用呢?下面会详细讲解到。

1 . C与M之间的关系调用。C指向M有一条绿色的线,这是直接调用关系。到实际的使用层面就是C可以通过import M的头文件任意使用M的公有API。M不能直接调用C,但是注意到了吗?model上面还有一个黄色的像小灯泡一样的东西,这个其实是M与C对话的一种间接方式。这种间接方式是什么呢?就是Notification & KVO。Notification是IOS里的另一个重要概念,C可以注册M的观察者,当M的数据发生改变后会发出通知使得它的观察者C接收到,然后做出一些响应(改变UI或者神马的);KVO(Key Value Observing)提供一种机制,当指定对象的属性被修改后,则接收到通知。Notification & KVO又是另一个可以深入探讨的话题,后续的博客也会写到。

2 . C与V之间的错综复杂的关系。C只想V也有一条绿色的线,也是直接调用关系。实际使用就是Controller可以持有View的一个指针,可以随意的调用View的公有API去改变View的展示。而View到Controller的通信代价就比较大了,具体有三种方式:

  第一种是目标操作 。target-action,view对于自己响应的action可以添加target方法,而target方法一定是存在在controller里面的方法,这样当view的某个动作发生后,就会去调用controller的方法,即view的target方法。例如,UIButton的按下操作的响应方法,可以addTarget一个方法,当按钮被按时调用这个方法,记住这个view是一个广义上的view,可以是你显示在屏幕上的一切东西,可以是系统提供的控件也可以是你自己写的view。

  第二种是委托。view制定自己的UI发生改变时的protocol,再声明一个weak的delegate属性,controller去实现view的protocol并做view的delegate。这样当它自己改变时就会询问view should I do sth?或者是当它will 或者 did change的时候就会去调用controller实现的委托方法了。委托也是IOS里面非常重要的一块内容,Coaoa提供的很多方法都是使用这种方式,比如UIAlertView。委托也会在后续博客中作为单独的一篇来写。

  第三种是数据源(data source)。V是数据的界面显示,但很显然view不可能自己拥有数据,所以在它的展示中会不断的向数据源去请求数据,而这种请求则需要通过controller来完成。比较典型的例子就是UITableView的实现,可以深入研究下(也可以作为单独的一篇来讲,比较重要)。


 下面来写段代码看一下MVC具体到代码级别到底是怎样的,V到C的调用以委托为例(很小的例子,但麻雀虽小,五脏俱全)

model的实现:

1 @interface MVCDemoModel : NSObject
2 @property(nonatomic , strong) NSString *name;
3 @end
 1 @implementation MVCDemoModel
 2 
 3 -(id)init
 4 {
 5     self = [super init];
 6     if (self) {
 7         _name = @"wangqing";
 8     }
 9     return self;
10 }
11 
12 @end

 view的实现:

 1 @protocol MVCDemoViewDelegate <NSObject>
 2 
 3 -(void)showModel;
 4 
 5 @end
 6 
 7 @interface MVCDemoView : UIView
 8 
 9 @property(nonatomic , weak)id<MVCDemoViewDelegate> delegate;
10 
11 @end
 1 @implementation MVCDemoView
 2 
 3 - (id)initWithFrame:(CGRect)frame
 4 {
 5     self = [super initWithFrame:frame];
 6     if (self) {
 7         UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(80, 200, 200, 80)];
 8         [button setTitle:@"click me" forState:UIControlStateNormal];
 9         [button setBackgroundColor:[UIColor blueColor]];
10         [button addTarget:self action:@selector(showTheModel) forControlEvents:UIControlEventTouchUpInside];
11         [self addSubview:button];
12     }
13     return self;
14 }
15 
16 - (void)showTheModel
17 {
18     if ([_delegate respondsToSelector:@selector(showModel)]) {
19         [_delegate showModel];
20     }
21 }
22 
23 @end

 controller的实现:

1 @interface ViewController : UIViewController<MVCDemoViewDelegate>
2 
3 @end
 1 @interface ViewController ()
 2 
 3 @property(nonatomic , strong) MVCDemoModel *demoModel;
 4 @property(nonatomic , strong) MVCDemoView *demoView;
 5 
 6 @end
 7 
 8 @implementation ViewController
 9 
10 - (void)viewDidLoad
11 {
12     [super viewDidLoad];
13     _demoView = [[MVCDemoView alloc]initWithFrame:self.view.frame];
14     [_demoView setDelegate:self];
15     [self.view addSubview:_demoView];
16     
17     _demoModel = [[MVCDemoModel alloc]init];
18 }
19 
20 - (void)showModel
21 {
22     NSLog(@"my name is %@",_demoModel.name);
23 }
24 
25 @end
复制代码

 讲解一下上面的代码,点击+号可以展开哟~也可以复制到工程中运行。

首先,可以看到Model与View没有直接的调用关系,二者不需要引用对方的头文件。可以看见,ViewController实现了MVCDemoView的delegate方法 showModel,而MVCDemoView中在点击button后会去找这个委托实现的方法,而该方法内,由于viewController用于model使用权,所以可以直接获取到model.name并打印到控制台。这样就完成了三者的一次交互。


上面的内容为转载http://www.cnblogs.com/xinguan/p/3505440.html,

在下面的例子中,View通过target-action模式向Controller传递消息,Controller通过API调用Model里面的方法来处理从View那接收到的消息;Model处理完数据之后,通过Notification模式向Controller传递一个消息,最终Controller通过一个方法(即Notification的接收方法)弹出来一个对话框显示Model已经处理完成。

1、 不使用MVC模式的案例:

1.1 使用Xcode创建一个Single View Application,命名为MVCsample。

1.2 在ViewController.h里面,添加如下代码:

  1. @property (nonatomicstrongUIButton *saveBtn; //点击该按钮,保存数据   

  2. @property (nonatomicstrongUIButton *loadBtn; //点击该按钮,加载数据  

如下图所示:

技术分享

1.3 在ViewController.m文件的- (void)viewDidLoad方法中,添加如下代码:

  1. _saveBtn = [UIButton buttonWithType:UIButtonTypeCustom];  

  2.   

  3. [_saveBtn setFrame:CGRectMake(505015080)];  

  4.   

  5. [_saveBtn setTitle:@"保存" forState:UIControlStateNormal];  

  6.   

  7. [_saveBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];  //默认的页面背景色是白色,butotn上的文字的默认颜色也是白色,所以在此处将button上的文字颜色设置为黑色,以便显示  

  8.   

  9.   

  10. [_saveBtn addTarget:self action:@selector(saveBtnPressed:) forControlEvents:UIControlEventTouchUpInside];  //添加target-action模式  

  11.   

  12. [self.view addSubview:_saveBtn];  

  13.   

  14.   

  15. _loadBtn = [UIButton buttonWithType:UIButtonTypeCustom];  

  16.   

  17. [_loadBtn setFrame:CGRectMake(5016015080)];  

  18.   

  19. [_loadBtn setTitle:@"加载" forState:UIControlStateNormal];  

  20.   

  21. [_loadBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];  

  22.   

  23. [_loadBtn addTarget:self action:@selector(loadBtnPressed:) forControlEvents:UIControlEventTouchUpInside];  //添加target-action模式  

  24.   

  25. [self.view addSubview:_loadBtn];  


如下图所示:


技术分享

1.4 在上面的一行代码中,我们分别为_saveBtn和_loadBtn添加了target-action模式,接下来在ViewController.m文件中实现这两个action方法,代码如下:

  1. - (void)saveBtnPressed : (UIButton*)sender{  

  2.       

  3.     NSLog(@"保存");  

  4.       

  5.     NSLog(@"当前设备的型号:%@", [[UIDevice currentDevice]systemVersion]);  

  6.       

  7.     /* 

  8.     //从iOS 8开始,苹果建议不使用UIAlertView和UIActionsheet,而是要使用UIAlertController。从iOS 9开始,UIAlertView和UIActionsheet更是已经被禁用,所以在这个案例中,虽然如下的UIAlertView方法还是可以照常运行,但我们还是遵从苹果的建议,使用新的技术和方法比较妥当 

  9.      

  10.     UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"恭喜" message:@"保存成功" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil]; 

  11.      

  12.     [alert show]; 

  13.       

  14.      */  

  15.       

  16.       

  17.     UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"恭喜"  

  18.                                                                              message:@"保存成功"  

  19.                                                                       preferredStyle:UIAlertControllerStyleAlert];  

  20.       

  21.     UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {  

  22.           

  23.         NSLog(@"点击了取消按钮");  

  24.           

  25.     }];  

  26.       

  27.     UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {  

  28.           

  29.         NSLog(@"点击了确定按钮");  

  30.           

  31.     }];  

  32.       

  33.     [alertController addAction:cancelAction];  

  34.     [alertController addAction:okAction];  

  35.       

  36.     [self presentViewController:alertController animated:YES completion:nil];  

  37.       

  38.       

  39.       

  40. }  

  41.   

  42. - (void)loadBtnPressed : (UIButton*)sender{  

  43.       

  44.     NSLog(@"加载");  

  45. }  


代码有点长,不再截图,各位请自行想象~~~



1.5 然后运行该程序,模拟器显示如下图:

技术分享

点击了“保存按钮”后,模拟器及Xcode输出台显示如下图所示:

技术分享


再点击AlertView上的“取消”或者“确定”按钮,Xcode输出台显示如下:

技术分享


以上内容,就是不使用MVC模式的情况下,我们经常做得内容。下面,我们就按照MVC的原理,来将改程序按照MVC的思想重新做一遍。


2. 使用MVC模式的案例:


2.1 使用Xcode创建一个Single View Application,命名为MVCsampleWithMVC;


2.2 新建三个文件夹(Group),分别命名为M、V和C;


2.3 新建一个名为VView的类,继承自UIView,并将UIView.h和UIView.m文件拖到V文件夹下;


2.4 新建一个名为MModel的类,继承自NSObject,并将MModel.h和MModelm文件拖到M文件夹下;


2.5 将ViewController.h和ViewController.m文件拖到C文件夹下。做完2.2~2.5的工作之后,Xcode工作组应该显示如下图所示:

技术分享


2.6 按照MVC的思想,V里面只存放界面显示的控件,在刚才的例子中,就是“保存”和“加载”这两个按钮,于是,我们把有关这两个按钮的代码都写到VView.h和VView.m中。

写好后的VView.h的代码如下:


[objc] view plaincopy

  1. #import <UIKit/UIKit.h>  

  2.   

  3. @interface VView : UIView  

  4.   

  5. @property (nonatomicstrongUIButton *saveBtn;  //点击该按钮,保存数据  

  6.   

  7. @property (nonatomicstrongUIButton *loadBtn;  //点击该按钮,加载数据  

  8.   

  9. - (void)viewInit;  //添加一个方法,用于初始化控件  

  10.   

  11. @end  


写好后的VView.m的代码如下:



[objc] view plaincopy

  1. #import "VView.h"  

  2.   

  3. @implementation VView  

  4.   

  5. - (void)viewInit {  

  6.       

  7.     _saveBtn = [UIButton buttonWithType:UIButtonTypeCustom];  

  8.       

  9.     [_saveBtn setFrame:CGRectMake(505015080)];  

  10.       

  11.     [_saveBtn setTitle:@"保存" forState:UIControlStateNormal];  

  12.       

  13.     [_saveBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];  //默认的页面背景色是白色,butotn上的文字的默认颜色也是白色,所以在此处将button上的文字颜色设置为黑色,以便显示  

  14.       

  15.     [self addSubview:_saveBtn];  

  16.       

  17.       

  18.     _loadBtn = [UIButton buttonWithType:UIButtonTypeCustom];  

  19.       

  20.     [_loadBtn setFrame:CGRectMake(5016015080)];  

  21.       

  22.     [_loadBtn setTitle:@"加载" forState:UIControlStateNormal];  

  23.       

  24.     [_loadBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];  

  25.       

  26.     [self addSubview:_loadBtn];  

  27.       

  28. }  

  29.   

  30. @end  


和上面的不使用MVC模式例子相比较,发现_saveBtn和_loadBtn都没有添加target-action方法。这是因为target-action方法需要设置一个target对象,在这个对象里调用action方法。按照MVC的思想,V里面不进行数据处理,而是要在C里面统一调控有C还是M来处理数据。本例中,我们是在C里面处理,所以我会把targe-action方法写到C里面,详细后面介绍。


2.7 按照MVC的思想,M主要用于数据的处理,我们假设这个案例是要将V中的某一段内容保存到数据库中,那么这个保存到数据库中的操作就是在M里面完成的。此处我们直接简化操作,只是写两个方法,用来提示保存和加载成功的。如此,MModel.h中的代码如下:


[objc] view plaincopy

  1. #import <Foundation/Foundation.h>  

  2.   

  3. @interface MModel : NSObject  

  4.   

  5. - (void)save;  

  6.   

  7. - (void)load;  

  8.   

  9. @end  


MModel.m中的代码如下:



[objc] view plaincopy

  1. #import "MModel.h"  

  2.   

  3. @implementation MModel  

  4.   

  5. - (void)save{  

  6.       

  7.     NSLog(@"保存。。。");  

  8.       

  9.     [[NSNotificationCenter defaultCenter] postNotificationName:@"saveSucessful" object:self];  //使用Notification模式发送一个通知,用于通知Controller要做什么事情  

  10.       

  11. }  

  12.   

  13. - (void)load{  

  14.       

  15.     NSLog(@"加载。。。");  

  16.       

  17. }  

  18.   

  19. @end  


可以看到,这段代码和不使用MVC模式的代码中的target-action方法中的action方法是基本上一样的。那么我么就会有一个思路——在Controller中,当我们为按钮添加了target-action模式之后,对应要实现的action方法里面,是不是只需要调用MModel.h里面的对应的- (void)save和- (void)load方法就行了呢?完全正确!看,这就是C通过API调用M!

在- (void)save方法中,我还使用Notification模式发送了一个通知,这个通知用来告知Controller,我已经保存好数据了,接下来你看着办!在上一个不使用MVC模式的例子中,Controller是弹出来一个Alert,本例子中,我们也要实现这个功能。


2.8 V和M都已经分配好了,接下来就是看C如何协调分配了。ViewController.h中的代码如下:

  1. #import <UIKit/UIKit.h>  

  2.   

  3. #import "VView.h"  

  4.   

  5. #import "MModel.h"  

  6.   

  7. @interface ViewController : UIViewController  

  8.   

  9.   

  10. @property (nonatomicstrongVView *aView;  //实例化一个VView的对象  

  11.   

  12. @property (nonatomicstrongMModel *mModel;  //实例化一个MModel的对象,以便于调用MModel中的方法  

  13.   

  14.   

  15. @end  


由于我在MModel.h中定义的方法都是实例方法,所以我们只能实例化一个MModel的对象来调用这些方法。如果将MModel中的方法设置为类方法或者单例模式,就可以直接用MModel这个类来调用了。


2.9 ViewContro.m中的代码如下:


[objc] view plaincopy

  1. #import "ViewController.h"  

  2.   

  3. #define deviceScreenWidth [[UIScreen mainScreen]bounds].size.width  

  4.   

  5. #define deviceScreenHeight [[UIScreen mainScreen]bounds].size.height  

  6.   

  7. @interface ViewController ()  

  8.   

  9. @end  

  10.   

  11. @implementation ViewController  

  12.   

  13. - (void)viewDidLoad {  

  14.     [super viewDidLoad];  

  15.       

  16.       

  17.     [[NSNotificationCenter defaultCenter] addObserver:self  

  18.                                              selector:@selector(saveOK:)  

  19.                                                  name:@"saveSucessful" object:nil];  //添加一个通知方法,当这个Controller接收到一个名称为@"saveSucessful"的通知后,就执行saveOK:方法  

  20.       

  21.       

  22.     _aView = [[VView alloc]initWithFrame:CGRectMake(00, deviceScreenWidth, deviceScreenHeight)];  //初始化时一定要设置frame,否则VView上的两个按钮将无法被点击  

  23.       

  24.     [_aView viewInit];  

  25.       

  26.     [_aView.saveBtn addTarget:self action:@selector(saveBtnPressed:) forControlEvents:UIControlEventTouchUpInside];  //为“保存”按钮添加target-action模式  

  27.       

  28.     [_aView.loadBtn addTarget:self action:@selector(loadBtnPressed:) forControlEvents:UIControlEventTouchUpInside];  //为“加载”按钮添加target-action模式  

  29.       

  30.     [self.view addSubview:_aView];  

  31.       

  32.     _mModel = [[MModel alloc]init];  

  33.       

  34.       

  35. }  

  36.   

  37.   

  38. - (void)saveBtnPressed : (UIButton*)sender{  

  39.       

  40.     [_mModel save];  //调用MModel.h中的方法(API)  

  41. }  

  42.   

  43. - (void)loadBtnPressed : (UIButton*)sender{  

  44.       

  45.     [_mModel load];  //调用MModel.h中的方法(API)  

  46. }  

  47.   

  48.   

  49. - (void)saveOK : (NSNotification*) notification{  

  50.       

  51.     UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"恭喜"  

  52.                                                                              message:@"保存成功"  

  53.                                                                       preferredStyle:UIAlertControllerStyleAlert];  

  54.       

  55.     UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {  

  56.           

  57.         NSLog(@"点击了取消按钮");  

  58.           

  59.     }];  

  60.       

  61.     UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {  

  62.           

  63.         NSLog(@"点击了确定按钮");  

  64.           

  65.     }];  

  66.       

  67.     [alertController addAction:cancelAction];  

  68.     [alertController addAction:okAction];  

  69.       

  70.     [self presentViewController:alertController animated:YES completion:nil];  

  71.       

  72.       

  73. }  

  74.   

  75. - (void)didReceiveMemoryWarning {  

  76.     [super didReceiveMemoryWarning];  

  77.     // Dispose of any resources that can be recreated.  

  78. }  

  79.   

  80. @end  


代码里面有一些注意事项,我都用注释的形式写在了代码的后面,请读者自行研究判断,此处不再赘述,有疑问欢迎留言讨论。从C的代码中可以看到,如何在MVC中使用target-action模式(delegate模式和data source模式,暂时不在这个案例中讲述),如何在C中调用M中的API,以及M如何通过Notification模式向C发送通知并由C处理相关的通知。虽然M+V+C里面的代码总量比不使用MVC模式多了一些,但MVC模式写出来的代码层次分明,结构清楚,分工明确,为以后修改代码、调试程序都带来了极大的便利。比如你要修改显示的效果,只需要修改V中的就行,然后按照调理在C中添加相应的方法,多么明确。使用MVC模式的运行效果我就不再附图了,亲测程序能正常工作,请读者自己也试一试吧,手动写写代码,对理解代码会有很大的帮助的。


1、 不使用MVC模式的案例:


1.1 使用Xcode创建一个Single View Application,命名为MVCsample。

1.2 在ViewController.h里面,添加如下代码:



[objc] view plaincopy

  1. @property (nonatomicstrongUIButton *saveBtn; //点击该按钮,保存数据   

  2. @property (nonatomicstrongUIButton *loadBtn; //点击该按钮,加载数据  





如下图所示:

技术分享

1.3 在ViewController.m文件的- (void)viewDidLoad方法中,添加如下代码:


[objc] view plaincopy

  1. _saveBtn = [UIButton buttonWithType:UIButtonTypeCustom];  

  2.   

  3. [_saveBtn setFrame:CGRectMake(505015080)];  

  4.   

  5. [_saveBtn setTitle:@"保存" forState:UIControlStateNormal];  

  6.   

  7. [_saveBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];  //默认的页面背景色是白色,butotn上的文字的默认颜色也是白色,所以在此处将button上的文字颜色设置为黑色,以便显示  

  8.   

  9.   

  10. [_saveBtn addTarget:self action:@selector(saveBtnPressed:) forControlEvents:UIControlEventTouchUpInside];  //添加target-action模式  

  11.   

  12. [self.view addSubview:_saveBtn];  

  13.   

  14.   

  15. _loadBtn = [UIButton buttonWithType:UIButtonTypeCustom];  

  16.   

  17. [_loadBtn setFrame:CGRectMake(5016015080)];  

  18.   

  19. [_loadBtn setTitle:@"加载" forState:UIControlStateNormal];  

  20.   

  21. [_loadBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];  

  22.   

  23. [_loadBtn addTarget:self action:@selector(loadBtnPressed:) forControlEvents:UIControlEventTouchUpInside];  //添加target-action模式  

  24.   

  25. [self.view addSubview:_loadBtn];  


如下图所示:


技术分享

1.4 在上面的一行代码中,我们分别为_saveBtn和_loadBtn添加了target-action模式,接下来在ViewController.m文件中实现这两个action方法,代码如下:


[objc] view plaincopy

  1. - (void)saveBtnPressed : (UIButton*)sender{  

  2.       

  3.     NSLog(@"保存");  

  4.       

  5.     NSLog(@"当前设备的型号:%@", [[UIDevice currentDevice]systemVersion]);  

  6.       

  7.     /* 

  8.     //从iOS 8开始,苹果建议不使用UIAlertView和UIActionsheet,而是要使用UIAlertController。从iOS 9开始,UIAlertView和UIActionsheet更是已经被禁用,所以在这个案例中,虽然如下的UIAlertView方法还是可以照常运行,但我们还是遵从苹果的建议,使用新的技术和方法比较妥当 

  9.      

  10.     UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"恭喜" message:@"保存成功" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil]; 

  11.      

  12.     [alert show]; 

  13.       

  14.      */  

  15.       

  16.       

  17.     UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"恭喜"  

  18.                                                                              message:@"保存成功"  

  19.                                                                       preferredStyle:UIAlertControllerStyleAlert];  

  20.       

  21.     UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {  

  22.           

  23.         NSLog(@"点击了取消按钮");  

  24.           

  25.     }];  

  26.       

  27.     UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {  

  28.           

  29.         NSLog(@"点击了确定按钮");  

  30.           

  31.     }];  

  32.       

  33.     [alertController addAction:cancelAction];  

  34.     [alertController addAction:okAction];  

  35.       

  36.     [self presentViewController:alertController animated:YES completion:nil];  

  37.       

  38.       

  39.       

  40. }  

  41.   

  42. - (void)loadBtnPressed : (UIButton*)sender{  

  43.       

  44.     NSLog(@"加载");  

  45. }  


代码有点长,不再截图,各位请自行想象~~~



1.5 然后运行该程序,模拟器显示如下图:

技术分享

点击了“保存按钮”后,模拟器及Xcode输出台显示如下图所示:

技术分享


再点击AlertView上的“取消”或者“确定”按钮,Xcode输出台显示如下:

技术分享


以上内容,就是不使用MVC模式的情况下,我们经常做得内容。下面,我们就按照MVC的原理,来将改程序按照MVC的思想重新做一遍。


2. 使用MVC模式的案例:


2.1 使用Xcode创建一个Single View Application,命名为MVCsampleWithMVC;


2.2 新建三个文件夹(Group),分别命名为M、V和C;


2.3 新建一个名为VView的类,继承自UIView,并将UIView.h和UIView.m文件拖到V文件夹下;


2.4 新建一个名为MModel的类,继承自NSObject,并将MModel.h和MModelm文件拖到M文件夹下;


2.5 将ViewController.h和ViewController.m文件拖到C文件夹下。做完2.2~2.5的工作之后,Xcode工作组应该显示如下图所示:

技术分享


2.6 按照MVC的思想,V里面只存放界面显示的控件,在刚才的例子中,就是“保存”和“加载”这两个按钮,于是,我们把有关这两个按钮的代码都写到VView.h和VView.m中。

写好后的VView.h的代码如下:


[objc] view plaincopy

  1. #import <UIKit/UIKit.h>  

  2.   

  3. @interface VView : UIView  

  4.   

  5. @property (nonatomicstrongUIButton *saveBtn;  //点击该按钮,保存数据  

  6.   

  7. @property (nonatomicstrongUIButton *loadBtn;  //点击该按钮,加载数据  

  8.   

  9. - (void)viewInit;  //添加一个方法,用于初始化控件  

  10.   

  11. @end  


写好后的VView.m的代码如下:



[objc] view plaincopy

  1. #import "VView.h"  

  2.   

  3. @implementation VView  

  4.   

  5. - (void)viewInit {  

  6.       

  7.     _saveBtn = [UIButton buttonWithType:UIButtonTypeCustom];  

  8.       

  9.     [_saveBtn setFrame:CGRectMake(505015080)];  

  10.       

  11.     [_saveBtn setTitle:@"保存" forState:UIControlStateNormal];  

  12.       

  13.     [_saveBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];  //默认的页面背景色是白色,butotn上的文字的默认颜色也是白色,所以在此处将button上的文字颜色设置为黑色,以便显示  

  14.       

  15.     [self addSubview:_saveBtn];  

  16.       

  17.       

  18.     _loadBtn = [UIButton buttonWithType:UIButtonTypeCustom];  

  19.       

  20.     [_loadBtn setFrame:CGRectMake(5016015080)];  

  21.       

  22.     [_loadBtn setTitle:@"加载" forState:UIControlStateNormal];  

  23.       

  24.     [_loadBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];  

  25.       

  26.     [self addSubview:_loadBtn];  

  27.       

  28. }  

  29.   

  30. @end  


和上面的不使用MVC模式例子相比较,发现_saveBtn和_loadBtn都没有添加target-action方法。这是因为target-action方法需要设置一个target对象,在这个对象里调用action方法。按照MVC的思想,V里面不进行数据处理,而是要在C里面统一调控有C还是M来处理数据。本例中,我们是在C里面处理,所以我会把targe-action方法写到C里面,详细后面介绍。


2.7 按照MVC的思想,M主要用于数据的处理,我们假设这个案例是要将V中的某一段内容保存到数据库中,那么这个保存到数据库中的操作就是在M里面完成的。此处我们直接简化操作,只是写两个方法,用来提示保存和加载成功的。如此,MModel.h中的代码如下:


[objc] view plaincopy

  1. #import <Foundation/Foundation.h>  

  2.   

  3. @interface MModel : NSObject  

  4.   

  5. - (void)save;  

  6.   

  7. - (void)load;  

  8.   

  9. @end  


MModel.m中的代码如下:



[objc] view plaincopy

  1. #import "MModel.h"  

  2.   

  3. @implementation MModel  

  4.   

  5. - (void)save{  

  6.       

  7.     NSLog(@"保存。。。");  

  8.       

  9.     [[NSNotificationCenter defaultCenter] postNotificationName:@"saveSucessful" object:self];  //使用Notification模式发送一个通知,用于通知Controller要做什么事情  

  10.       

  11. }  

  12.   

  13. - (void)load{  

  14.       

  15.     NSLog(@"加载。。。");  

  16.       

  17. }  

  18.   

  19. @end  


可以看到,这段代码和不使用MVC模式的代码中的target-action方法中的action方法是基本上一样的。那么我么就会有一个思路——在Controller中,当我们为按钮添加了target-action模式之后,对应要实现的action方法里面,是不是只需要调用MModel.h里面的对应的- (void)save和- (void)load方法就行了呢?完全正确!看,这就是C通过API调用M!



在- (void)save方法中,我还使用Notification模式发送了一个通知,这个通知用来告知Controller,我已经保存好数据了,接下来你看着办!在上一个不使用MVC模式的例子中,Controller是弹出来一个Alert,本例子中,我们也要实现这个功能。


2.8 V和M都已经分配好了,接下来就是看C如何协调分配了。ViewController.h中的代码如下:


[objc] view plaincopy

  1. #import <UIKit/UIKit.h>  

  2.   

  3. #import "VView.h"  

  4.   

  5. #import "MModel.h"  

  6.   

  7. @interface ViewController : UIViewController  

  8.   

  9.   

  10. @property (nonatomicstrongVView *aView;  //实例化一个VView的对象  

  11.   

  12. @property (nonatomicstrongMModel *mModel;  //实例化一个MModel的对象,以便于调用MModel中的方法  

  13.   

  14.   

  15. @end  


由于我在MModel.h中定义的方法都是实例方法,所以我们只能实例化一个MModel的对象来调用这些方法。如果将MModel中的方法设置为类方法或者单例模式,就可以直接用MModel这个类来调用了。


2.9 ViewContro.m中的代码如下:


[objc] view plaincopy

  1. #import "ViewController.h"  

  2.   

  3. #define deviceScreenWidth [[UIScreen mainScreen]bounds].size.width  

  4.   

  5. #define deviceScreenHeight [[UIScreen mainScreen]bounds].size.height  

  6.   

  7. @interface ViewController ()  

  8.   

  9. @end  

  10.   

  11. @implementation ViewController  

  12.   

  13. - (void)viewDidLoad {  

  14.     [super viewDidLoad];  

  15.       

  16.       

  17.     [[NSNotificationCenter defaultCenter] addObserver:self  

  18.                                              selector:@selector(saveOK:)  

  19.                                                  name:@"saveSucessful" object:nil];  //添加一个通知方法,当这个Controller接收到一个名称为@"saveSucessful"的通知后,就执行saveOK:方法  

  20.       

  21.       

  22.     _aView = [[VView alloc]initWithFrame:CGRectMake(00, deviceScreenWidth, deviceScreenHeight)];  //初始化时一定要设置frame,否则VView上的两个按钮将无法被点击  

  23.       

  24.     [_aView viewInit];  

  25.       

  26.     [_aView.saveBtn addTarget:self action:@selector(saveBtnPressed:) forControlEvents:UIControlEventTouchUpInside];  //为“保存”按钮添加target-action模式  

  27.       

  28.     [_aView.loadBtn addTarget:self action:@selector(loadBtnPressed:) forControlEvents:UIControlEventTouchUpInside];  //为“加载”按钮添加target-action模式  

  29.       

  30.     [self.view addSubview:_aView];  

  31.       

  32.     _mModel = [[MModel alloc]init];  

  33.       

  34.       

  35. }  

  36.   

  37.   

  38. - (void)saveBtnPressed : (UIButton*)sender{  

  39.       

  40.     [_mModel save];  //调用MModel.h中的方法(API)  

  41. }  

  42.   

  43. - (void)loadBtnPressed : (UIButton*)sender{  

  44.       

  45.     [_mModel load];  //调用MModel.h中的方法(API)  

  46. }  

  47.   

  48.   

  49. - (void)saveOK : (NSNotification*) notification{  

  50.       

  51.     UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"恭喜"  

  52.                                                                              message:@"保存成功"  

  53.                                                                       preferredStyle:UIAlertControllerStyleAlert];  

  54.       

  55.     UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {  

  56.           

  57.         NSLog(@"点击了取消按钮");  

  58.           

  59.     }];  

  60.       

  61.     UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {  

  62.           

  63.         NSLog(@"点击了确定按钮");  

  64.           

  65.     }];  

  66.       

  67.     [alertController addAction:cancelAction];  

  68.     [alertController addAction:okAction];  

  69.       

  70.     [self presentViewController:alertController animated:YES completion:nil];  

  71.       

  72.       

  73. }  

  74.   

  75. - (void)didReceiveMemoryWarning {  

  76.     [super didReceiveMemoryWarning];  

  77.     // Dispose of any resources that can be recreated.  

  78. }  

  79.   

  80. @end  


代码里面有一些注意事项,我都用注释的形式写在了代码的后面,请读者自行研究判断,此处不再赘述,有疑问欢迎留言讨论。从C的代码中可以看到,如何在MVC中使用target-action模式(delegate模式和data source模式,暂时不在这个案例中讲述),如何在C中调用M中的API,以及M如何通过Notification模式向C发送通知并由C处理相关的通知。虽然M+V+C里面的代码总量比不使用MVC模式多了一些,但MVC模式写出来的代码层次分明,结构清楚,分工明确,为以后修改代码、调试程序都带来了极大的便利。比如你要修改显示的效果,只需要修改V中的就行,然后按照调理在C中添加相应的方法,多么明确。使用MVC模式的运行效果我就不再附图了,亲测程序能正常工作,请读者自己也试一试吧,手动写写代码,对理解代码会有很大的帮助的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值