iOS平台上的MVVM模式(译文)

转载自:http://www.teehanlax.com/blog/model-view-viewmodel-for-ios/ios

Written by Ash Furrow on January 14,2014 in Development设计模式

若是你在iOS平台上有必定开发经验,必定据说过Model-View-Controller,或称MVC模式,MVC是构建iOS应用的标准设计模式。但实际开发中,MVC暴露出许多的缺陷。网络

经过这篇文章,我会介绍什么是MVC,以及MVC的缺陷。对于如何解决MVC的这些缺陷,我会介绍一种全新设计模式:Model-View-ViewModel,即MVVM。mvc

1 MVC模式及其缺陷

1.1 MVC模式简介

苹果官方称MVC设计模式(简称MVC)是iOS应用设计的最佳模式。异步

在MVC中,任何对象均可被归为模型对象、视图对象或控制器对象。模型对象(Model Object,简称模型)持有程序数据;视图对象(View Object,简称视图)负责用户交互;控制器对象(Controller Object,简称控制器)则做为模型和视图沟通的媒介。mvvm

视图将用户输入转交给控制器,由控制器按照相应请求通知模型进行更新,模型将自身数据变化通知(一般经过KVO的途径)控制器,最后控制器操做视图进行相应的更新(以下图所示):单元测试

mvc

模型一般十分简洁,大多数状况下它们由Core Data管理。根据苹果的描述,模型中封装了数据以及对数据的操做代码。实际工做中使用的模型对象一般都很小,但数据操做代码时常会被耦合到控制器中。测试

视图是UIKit对象或自定义对象,它是程序中的可视部分,一般存在于.xib文件或storyboard中,好比按钮或标签。视图不该同模型直接交互,而只能经过控制器的IBAction事件进行间接交互,而且非视图逻辑不该写在视图中。设计

控制器至关于胶水代码,将模型和视图粘合在一块儿。控制器负责控制视图的加载,显示,隐藏等。在控制器中还存在控制模型的代码,以及那些既不属于模型对象又不属于视图对象的代码,从而引出MVC模式的第一个缺陷。对象

1.2 MVC的缺陷

1.2.1 臃肿的控制器

控制器的功能决定了其内部既包含视图控制又包含模型控制,这使得控制器十分臃肿。

千上万行代码挤在一个控制器内,致使代码不易维护。好比一个控制器有数十个属性,要管理它的各类状态就十分困难。再好比一个控制器接受了若干协议,那其中就可能既包含协议方法代码,又包含控制器自身的控制逻辑。

另一个结果是程序不易测试(不管是手动测试仍是单元测试),由于控制器拥有太多不一样的状态,没法将全部状态都覆盖到。

1.2.2 网络逻辑无处可放

若是程序中全部对象都被纳入MVC,那么问题来了:网络代码应归为哪一类?API通讯代码又归为哪一类?

假设网络代码被放在模型中,因为网络请求必须支持异步完成,若是模型已经消失,而网络请求还在继续,那这个问题就复杂了。

另外,网络代码不可能放在视图中,那就只剩一个地方了:控制器。但把网络代码放在控制器中的作法很糟糕,这样会加重以前提到的问题:臃肿的控制器。

那么,到底该将网络代码放在何处?MVC中并无提供解决方案。

1.2.3 代码难以测试

MVC另一个问题是它不利于测试。控制器中混合了操做逻辑和业务逻辑,想要将这两者分离进行测试会十分困难。固然,许多人都有办法忽略这个问题,即不进行任何测试。

1.2.4 模糊的管理

控制器管理着一个视图树,经过IBOutlet还能够访问任意子视图,但当使用控制器管理大量子视图时,用outlet来访问就显得过于复杂了,一个解决办法是添加子控制器管理子视图。

不管怎么作,控制器和对应的视图都紧密耦合,固然也能够把它们两者就看作一个总体。

不过,能够看看下面这个办法。

2 MVVM模式

也许在理想状态下MVC会有很好的效果,但现实中它却不尽如人意。

咱们已经对MVC模式有了详细了解,下面就介绍它的替代方案:Model-View-ViewModel(MVVM)模式。

MVVM由微软公司提出(先不要对它产生偏见),它和MVC模式有许多相同之处。MVVM将视图和控制器的耦合部分抽取出来,从而引入一个新的部分,即View-Model(VM)。

mvvm

在MVVM模式下,视图及控制器形式上关联在一块儿,故可将两者视为一个总体。视图仍不会同模型直接交互,但控制器也没有同模型直接交互,取而代之的是视图模型(ViewModel)。

诸如验证用户输入请求、视图的显示逻辑、剥离网络请求或其余相似代码,将它们放在视图模型中再合适不过了,而且视图模型中没有对视图的直接引用。

视图模型中封装的代码既能够工做在iOS下,也能够工做在OSX下(换句话说就是不要在视图模型中引入和具体平台有关的内容,如#import UIKit.h)。

因为将视图逻辑——好比说将模型中的某些值映射为一个字符串的操做,都放在了视图模型中,故大大下降了控制器的复杂程度和它与其余部分的耦合程度。

使用MVVM的最大好处是,你能够先放入一小部分逻辑到视图模型中,随着对模式了解的深刻,慢慢再将其余代码迁移到其中。

MVVM模式对测试十分友好。因为视图模型中包含了全部的显示逻辑,而且没有任何对于视图的直接引用,故彻底能够自动化测试,而且使用MVVM的程序能够充分地运行单元测试。

就我使用MVVM的经验来看,这种模式会形成代码量稍稍提高,可是代码复杂程度获得极大下降,孰优孰劣一目了然。

本文中屡次在不一样地方使用到了“通知”和“更新”,但没有说明如何进行这样的操做。你能够在MVC模式中使用KVO来进行这样的操做,但代码会很快变得难以管理。实际工做中,更倾向于在MVVM中使用ReactiveCocoa来将全部的部分关联到一块儿。

相关文章
相关标签/搜索