iOS 我理解的MVC和MVVM

一、MVC模式

MVC模式算是老生常谈的开发模式了,简单的说,M单纯的数据模型,V就是视图,例如一个UIButton、一个列表视图Table或者自定义封装的View等,C则是controller控制器,它是M和V的纽带,负责业务逻辑部分,包括处理M数据模型、管理V视图(创建、展示、释放等)、响应V的事件等等。MVC的本质就是将数据的存储M和数据的展示V进行隔离,以提高代码的复用性和扩展性。

MVC
借用别人的图

MVC模式大体如上图所示。我们可以看到,Controller可以和Model、View进行通信,而Model和View是相互隔离的,它们的关联都是通过Controller来实现的,这样一来,就可以提高两者的复用性和可扩展性,即相同的Model可以有不同的展现形式,同样的,相同的View可以有不同的模型数据,达到了解耦和重用的目的。
如果Model发生了变化,那么就通过Notification和KVO的方式传递给Controller,Controller可以直接根据Model决定View的展示形式。View如果接受响应事件则通过delegate,target-action,block等方式告诉Controller的状态变化。Controller进行业务的处理,然后再控制View的展示。

举例说明:
我们假设苹果根据买iPhone的人给予不同的优惠,学生优惠20%,it民工优惠50%,其他不优惠。

//客户类

typedef NS_ENUM(NSInteger, CustomerType) {
    CustomerTypeStudent,
    CustomerTypeiT,
    CustomerTypeOther,
};

@interface Customer : NSObject

@property (nonatomic, assign) CustomerType customerType;

@end

//iPhone类

@interface iPhone : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *price;

@end

//VC类

@interface ViewController ()

@property (nonatomic, strong) iPhone *iphone;
@property (nonatomic, strong) Customer *customer;

@property (weak, nonatomic) IBOutlet UILabel *lblName;
@property (weak, nonatomic) IBOutlet UILabel *lblPrice;
@property (weak, nonatomic) IBOutlet UILabel *lblDiscount;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.title = @"手机优惠";

    self.lblName.text = self.iphone.name;
    self.lblPrice.text = self.iphone.price;

    if (self.customer.customerType == CustomerTypeStudent) {
        self.lblDiscount.text = @"优惠20%";
    }
    else if (self.customer.customerType == CustomerTypeiT) {
        self.lblDiscount.text = @"优惠50%";
    }
    else {
        self.lblDiscount.text = @"没有优惠";
    }
}

@end

这是我们开发过程中最经典的MVC案例,将业务逻辑部分全都写在Controller类里面,根据Model模型来展示View。这样做是没有错的,但是如果业务逻辑相当复杂,代码又不规范、没有调理性,开发下来,controller会变得相当的臃肿,越来越难维护。即使做好了相关的代码分类和注释,整个业务逻辑看起来也是相当的头疼,因为有些业务处理并不是我们想要关注的。


二、MVVM模式

针对MVC的缺陷,MVVM模式出现了,既然我们并不太想关注业务是怎么实现的,我们能不能将业务实现的部分分离出来,当我想要某个业务的时候(比如数据的获取处理成Model、按钮事件的响应、页面的跳转等),我只需要告知其就可以了,这样的Controller只包含了业务逻辑部分,而具体的实现部分则是透明的,Controller并不需要关心怎么实现,这样,Controller变得相当清爽,我们的业务部分相当清晰。


MVVM

这样看来,MVVM中的VM就是Controller+Model(具有业务实现功能),MVVM其实应该叫做MVCM,可能是因为在这样的模型下,Controller的管理功能被转移削弱,只负责View的管理等部分功能而使用V来定义吧。
从图上看出,View-Model是Controller业务的代理者,而原来的Controller不再直接接触Model,Model的拥有者已然移交给了View-Model。

原来的例子使用MVVM:

//新建一个viewModel
//.h文件

@interface viewModel : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *price;
@property (nonatomic, strong) NSString *discount;

- (id)initWithCustomer:(Customer *)customer iphone:(iPhone *)iphone;

@end

//.m文件

@interface viewModel ()

@property (nonatomic, strong) iPhone *iphone;
@property (nonatomic, strong) Customer *customer;

@end

@implementation viewModel

- (id)initWithCustomer:(Customer *)customer iphone:(iPhone *)iphone
{
    if (self = [super init]) {
        _customer = customer;
        _iphone = iphone;
        [self bindData];
    }
    return self;
}

- (void)bindData
{
    self.name = _iphone.name;
    self.price = _iphone.price;

    if (self.customer.customerType == CustomerTypeStudent) {
        self.discount = @"优惠20%";
    }
    else if (self.customer.customerType == CustomerTypeiT) {
        self.discount = @"优惠50%";
    }
    else {
        self.discount = @"没有优惠";
    }
}

@end

//VC

@interface ViewController ()

@property (nonatomic, strong) viewModel *viewModel;

@property (weak, nonatomic) IBOutlet UILabel *lblName;
@property (weak, nonatomic) IBOutlet UILabel *lblPrice;
@property (weak, nonatomic) IBOutlet UILabel *lblDiscount;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.title = @"手机优惠";

    self.lblName.text = self.viewModel.name;
    self.lblPrice.text = self.viewModel.price;
    self.lblDiscount.text = self.viewModel.discount;

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

比较可以看出,Controller里面仅仅做了展示数据的操作,而这数据怎么来的,Controller并不关心,而这部分的业务逻辑移交给了viewModel来处理,而viewModel则将处理结果开放出来,通过属性或者代理、block回调传给Controller。


三、MVVM优缺点

优点:

1、简化Controller业务逻辑

它可以为Controller分担部分业务,瘦身Controller,让开发者不再需要在Controller里寻找业务的实现部分,而关注Controller的业务流程。

缺点

1、类数量增加、复用性差

实际上,View-Model只是一个特殊的业务类(例如数据请求类),特殊性就在于,它的针对性强,是Controller的业务代理者,通常一个VC都分配一个View-Model,所以View-Model通常不复用。

2、调用复杂度增加

由于数据都是从viewModel来,想想突然来了一个新人,一看代码,不知道真实的模型是谁。比如常用tableview的数据源,一般都是一个数组,如果不断的通过viewModel去取,沟通上没有那么直接。况且每封一层,意味着要写很多代码去融合他们的转换。

四、体会

1、在业务简单的页面,使用MVC最合适,Controller直接处理业务,调用Model便捷。

2、业务复杂的页面最好使用MVVM,这样业务模块化,管理方便,简化Controller。

3、最重要一点,MVVM中的viewModel是Controller业务逻辑的分担者,请基于MVC原则下尝试MVVM


五、鸣谢

1、非常感谢作者:JamesYu,对MVVM模式解释的很好,举的例子也非常好,很容易理解。

2、原文地址:谈谈MVC和MVVM

3、如果我理解的不对的地方,还望大家指正,谢谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容