一、MVC阐述
1.MVC(Model、View、Controller),即模型、视图、控制器;
-
Model:
模型对象封装了应用程序的数据,并定义操控和处理该数据的逻辑和运算。例如,模型对象可能是表示商品数据 list。用户在视图层中所进行的创建或修改数据的操作,通过控制器对象传达出去,最终会创建或更新模型对象。模型对象更改时(例如通过网络连接接收到新数据),它通知控制器对象,控制器对象更新相应的视图对象。 -
View:
视图对象是应用程序中用户可以看见的对象。视图对象知道如何将自己绘制出来,可能对用户的操作作出响应。视图对象的主要目的就是显示来自应用程序模型对象的数据,并使该数据可被编辑。尽管如此,在 MVC 应用程序中,视图对象通常与模型对象分离。 -
Controller:
在应用程序的一个或多个视图对象和一个或多个模型对象之间,控制器对象充当媒介。控制器对象因此是同步管道程序,通过它,视图对象了解模型对象的更改,反之亦然。控制器对象还可以为应用程序执行设置和协调任务,并管理其他对象的生命周期。
控制器对象解释在视图对象中进行的用户操作,并将新的或更改过的数据传达给模型对象。模型对象更改时,一个控制器对象会将新的模型数据传达给视图对象,以便视图对象可以显示它。
2.实例描述
- 比如在iOS程序中,视图、按钮、弹框等都对应View,承载数据特征或数据处理逻辑的Object对应Model,通常一个页面下会用到多个View和Model,如根据条件展示不同的弹框,这个时候就需要一个管理者来管理他们,也就是需要一个控制器,那么iOS中的ViewController就对应上面所说的Controller。
就比如画画一样,有模特、画师、画板
-
需要展现的是模特的身材、样貌、气质等特征,那么模特就对应Model,他封装了要展示的数据;
-
画板需要将模特的身材、样貌、气质等特征呈现出来,对应View;
-
而画师则负责在两者之间做传递,画师需要将自己所看到的模特的样子画在画板上,如果模特换了个姿势,换了套衣服,会影响画师去调整或更换画板,同时画板的成像效果也会影响到画师来通知模特做些调整,比如保持微笑等,,画师对应Controller
3.MVC 的几个明显的特征和体现:
- View上展示什么东西取决于Model
- 只要 Model 数据改了,View 的显示状态会跟着更改
- Controller 负责初始化 Model和VIew,并将 Model 传递给 View 去解析展示
4.简单的 MVC
- 控制器加载模型数据并将数据转换为数据模型。
- 控制器创建视图控件,并将模型数据传递给视图控件
![](https://img.haomeiwen.com/i10955028/1d4964d110245cf5.png)
二、iOS中的标准MVC
1.比如iOS中的如下例子
- 创建一个TestView
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface TestView : UIView
@property (nonatomic, strong) UILabel *nameLb;
@end
NS_ASSUME_NONNULL_END
#import "TestView.h"
@implementation TestView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self addSubview:self.nameLb];
}
return self;
}
- (UILabel*)nameLb
{
if (!_nameLb) {
_nameLb = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 80, 30)];
_nameLb.center = self.center;
_nameLb.textAlignment = NSTextAlignmentCenter;
}
return _nameLb;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end
- 创建一个Model
#import <Foundation/Foundation.h>
@interface ZYModel : NSObject
@property (nonatomic, copy) NSString *name;
@end
#import "ZYModel.h"
@implementation ZYModel
@end
- 创建一个Controller
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
#import "ViewController.h"
#import "ZYModel.h"
#import "TestView.h"
@interface ViewController ()
@property (nonatomic, strong) ZYModel *zyModel;
@property (nonatomic, strong) TestView *testView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self loadData];
[self initTestView];
}
- (void)loadData
{
self.zyModel = [[ZYModel alloc] init];
self.zyModel.name = @"赵扬扬";
}
- (void)initTestView
{
self.testView = [[TestView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
self.testView.center = self.view.center;
self.testView.nameLb.text = self.zyModel.name;
[self.view addSubview:self.testView];
}
@end
由上图的例子可以看出,控制器加载模型数据并将数据转换为数据模型。控制器创建视图控件,并将模型数据传递给视图控件
但在实际应用过程中,由于不可避免的交互,数据和界面都会出现更新,因此就会产生通信,在iOS中,MVC模式的通信关系如下图所示
![](https://img.haomeiwen.com/i10955028/543ff70e602dcb66.png)
-
Model 和 View 永远不能相互通信,只能通过 Controller 传递。
-
Controller 可以直接与 Model 对话(读写调用 Model),Model 通过 Notification 和 KVO 等机制与 Controller 间接通信。
-
Controller 可以直接与 View 对话,通过 outlet,直接操作 View,outlet 直接对应到 View 中的控件,View 通过 action 向 Controller 报告事件的发生(如用户 Touch 我了)。Controller 是 View 的直接数据源(数据很可能是 Controller 从 Model 中取得并经过加工了)。Controller 是 View 的代理(delegate),以同步 View 与 Controller。
比如在上面的iOS例子中,如果ZYModel中的name属性改变了,由赵扬扬变成了扬扬,那么TestView上就不能再展示为赵扬扬了,要变成扬扬,这个流程如下:ZYModel通过一种方式告知ViewCotroller我的name改变了,然后由ViewCotroller去告知TestView去更新展示,同样的道理,如果是TestView由于用户的交互要改变ZYModel的name,也是通过ViewCotroller去传达。如下图
![](https://img.haomeiwen.com/i10955028/6acf1347215a4717.png)
三、MVC变种
在上面的例子中,ZYModel只有一个属性,TestView也只有一个nameLb属性,控制器传值的时候是将ZYModel的对象数据传给TestView的对应属性或控件,但如果ZYModel和TestView都拥有多个属性,那么按照上面所说的模式则只能一一对应传值,而且TestView需要将它需要更新的属性全部暴露出来!
@interface TestView : UIView
@property (nonatomic, strong) UILabel *nameLb;
@property (nonatomic, strong) UILabel *ageLb;
@property (nonatomic, strong) UILabel *sexLb;
@end
@interface ZYModel : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *age;
@property (nonatomic, copy) NSString *sex;
@end
在VIewController中将这些传值
self.testView.nameLb.text = self.zyModel.name;
self.testView.ageLb.text = self.zyModel.age;
self.testView.sexLb.text = self.zyModel.sex;
由上面的例子可以看出,如果属性很多、模型也不知一个,这样一来Controller中的代码会非常臃肿,所以通常我们开发中会做一些改动,让View依赖于Model,将View内部的细节封装起来!如下图所示
![](https://img.haomeiwen.com/i10955028/3cc7fc960561f2c7.png)
相对于标准的MVC,变种过的MVC中由于View依赖于Model,所以View的独立性和可复用性不如标准MVC中的View高
但变种MVC的控制器代码更精简一些,View的封装性更好一些。
总结
在实际开发中,如果采用MVC模式,往往会造成控制器比较臃肿,因为往往一个控制器需要承载和管理多个View和Model,再者,这几层之间耦合比较严重,不利于大型项目的维护,其灵活性也比较差。在实际应用中,应尽量给控制器瘦身、抽离业务逻辑。以免代码臃肿、耦合严重!
网友评论