iOS架构设计之MVC

一、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
  • 控制器加载模型数据并将数据转换为数据模型。
  • 控制器创建视图控件,并将模型数据传递给视图控件
MVC结构图

二、iOS中的标准MVC

1.比如iOS中的如下例子
  • 创建一个TestView
#import 

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 

@interface ZYModel : NSObject

@property (nonatomic, copy) NSString *name;

@end
#import "ZYModel.h"

@implementation ZYModel

@end
  • 创建一个Controller
#import 

@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模式的通信关系如下图所示


iOSMVC
  • 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去传达。如下图

iOS标准MVC通信流程

三、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内部的细节封装起来!如下图所示

iOS中MVC的变种

相对于标准的MVC,变种过的MVC中由于View依赖于Model,所以View的独立性和可复用性不如标准MVC中的View高

但变种MVC的控制器代码更精简一些,View的封装性更好一些。

总结

在实际开发中,如果采用MVC模式,往往会造成控制器比较臃肿,因为往往一个控制器需要承载和管理多个View和Model,再者,这几层之间耦合比较严重,不利于大型项目的维护,其灵活性也比较差。在实际应用中,应尽量给控制器瘦身、抽离业务逻辑。以免代码臃肿、耦合严重!

你可能感兴趣的:(iOS架构设计之MVC)