作为一个iOS开发者,我不止一次听到我的一些开发者朋友跟我说我写的iOS代码看起来好舒服,很整洁,为什么咱们iOS开发的相当一大部分应用软件都给人以美的享受,究竟是什么使得iOS上的应用可以如此漂亮?因为他们使用了将代码和界面分开的开发结构框架MVC。

MVC的低耦合性、高重用性、可维护性等优点显而易见,使得原本复杂的代码与界面的交互变得简单、清晰、明了,开发者可以把更多的精力放在前端界面的设计上,而不用绞尽脑汁去思考究竟应该如何使界面得到同步,这样减轻了设计压力,也从另一方面使用户得到更多更好的享受体验。纵观iOS经典Native App的所有应用软件,几乎都具有一个很大特点,那就是“炫”。清新的画面配以简单的手势操作,颠覆着用户的思维方式,小巧精悍。

MVC是构建iOS app的标准模式。但是,各位朋友们,如果你已经使用过MVC一段时间,我觉得越来越厌倦MVC的一些缺点。在本文,我将重温一下MVC是什么,详述它的缺点,并且告诉你一个新的方式来架构你的app:Model-View-ViewModel。

MVC即是Model-VIew-Controller三个英文单词的缩写,中文翻译为模型-视图-控制器。MVC并非只有ios应用软件独有的应用开发模式,它被广泛应用在许多软件(尤其是中大型软件)的开发上。MVC把软件系统分为三个部分:Model,View,Controller。Model相当于应用的底层,应用在功能上的实现完全依赖于Model,打个比方,如果是一台电脑的话,Model就是你机箱里的所有东西:cpu,内存,硬盘,显卡等的一个集合,你不必看到它们,但它们必不可少;Controller就是控制器,它控制Model与View的交互,它将M和V捆绑在一起,将你的操作传达给Model,再控制View将其表现出来。View相当于电脑的图形界面,将Model的运行结果可视化地呈现给用户,你在屏幕上看到的一切都可以归类于View。

在cocoa中,你的程序中的每一个object(对象)都将明显地仅属于这三部分中的一个,而完全不属于另外两个。因此,用MVC开发的应用软件更易于进行维护和修改,不用因为底层的Model出了问题而去影响表层的View。MVC虽然把三部分独立了出来,但三部分之间仍然存在联系,但就如下图所示,Model与View之间是完全独立的,两者各自运行,以Controller为桥梁进行交互,并不发生直接关联。

在这种架构下,View 是无状态的,在 Model 变化的时候它只是简单的被 Controller 重绘;就像网页一样,点击了一个新的链接,整个网页就重新加载。尽管这种架构可以在 iOS 应用里面实现,但是由于 MVC 的三种实体被紧密耦合着,每一种实体都和其他两种有着联系,所以即便是实现了也没有什么意义。这种紧耦合还戏剧性的减少了它们被重用的可能,这恐怕不是你想要在自己的应用里面看到的。综上,传统 MVC 的例子我觉得也没有必要去写了。

传统的 MVC 已经不适合当下的 iOS 开发了。

View 和 Model 之间是相互独立的,它们只通过 Controller 来相互联系。有点恼人的是 Controller 是重用性最差的,因为我们一般不会把冗杂的业务逻辑放在 Model 里面,那就只能放在 Controller 里了。

理论上看这么做貌似挺简单的,但是你有没有觉得有点不对劲?你甚至听过有人把 MVC 叫做重控制器模式。另外 关于 ViewController 瘦身 已经成为iOS 开发者们热议的话题了。为什么 Apple 要沿用只是做了一点点改进的传统 MVC 架构呢?

Cocoa MVC 鼓励你去写重控制器是因为 View 的整个生命周期都需要它去管理,Controller 和 View 很难做到相互独立。虽然你可以把控制器里的一些业务逻辑和数据转换的工作交给 Model,但是你再想把负担往 View 里面分摊的时候就没办法了;因为 View 的主要职责就只是讲用户的操作行为交给Controller 去处理而已。于是 ViewController 最终就变成了所有东西的代理和数据源,甚至还负责网络请求的发起和取消。

MVC以下几点是真的让人很头疼!!

厚重的View Controller

由于大量的代码被放进view controller,导致他们变的相当臃肿。在iOS中有的view controller里绵延成千上万行代码的事并不是前所未见的。这些超重app的突出情况包括:厚重的View Controller很难维护(由于其庞大的规模);包含几十个属性,使他们的状态难以管理;遵循许多协议(protocol),导致协议的响应代码和controller的逻辑代码混淆在一起。

厚重的view controller很难测试,不管是手动测试或是使用单元测试,因为有太多可能的状态。将代码分解成更小的多个模块通常是件好事。

遗失的网络逻辑

苹果使用的MVC的定义是这么说的:所有的对象都可以被归类为一个model,一个view,或是一个controller。就这些。那么把网络代码放哪里?和一个API通信的代码应该放在哪儿?

你可能试着把它放在model对象里,但是也会很棘手,因为网络调用应该使用异步,这样如果一个网络请求比持有它的model生命周期更长,事情将变的复杂。显然也不应该把网络代码放在view里,因此只剩下controller了。这同样是个坏主意,因为这加剧了厚重View Controller的问题。

那么应该放在那里呢?显然MVC的3大组件根本没有适合放这些代码的地方。

较差的可测试性

MVC的另一个大问题是,它不鼓励开发人员编写单元测试。由于view controller混合了视图处理逻辑和业务逻辑,分离这些成分的单元测试成了一个艰巨的任务。大多数人选择忽略这个任务,那就是不做任何测试。

定义模糊的“Manage”

之前我提到了view controller可以管理试图的层次结构;view controller有一个“view”属性,并且可以通过IBOutlet访问视图的任何子视图。当有很多outlet时这样做不易于扩展,在某种意义上,最好不要使用子视图控制器(child view controller)来帮助管理子视图(subview)。

要点在哪?验证用户输入的业务逻辑应归入controller还是model呢?

在这里有多个模糊的标准,似乎没有人能完全达成一致。貌似无论如何,view和对应的controller都紧紧的耦合在一起,总之,还是会把它们当成一个组件来对待。

Hey!现在有个点子...

Model-View-ViewModel

在理想的世界里,MVC也许工作的很好。然而,我们生活在真实的世界。既然我们已经详细说明了MVC在典型场景中的问题,那让我们看一看一个可供替换的选择:Model-View-ViewModel。

MVVM来自微软,不过不要坚持反对它。MVVM和MVC很像。它正式规范了视图和控制器紧耦合的性质,并引入新的组件。

在MVVM里,view和view controller正式联系在一起,我们把它们视为一个组件。视图view仍然不能直接引用模型model,当然controller也不能。相反,他们引用视图模型view model。

view model是一个放置用户输入验证逻辑,视图显示逻辑,发起网络请求和其他各种各样的代码的极好的地方。有一件事情不应归入view model,那就是任何视图本身的引用。view model的概念同时适用于于iOS和OS X。(换句话说,不要在view model中使用 #import UIKit.h)

由于展示逻辑(presentation logic)放在了view model中(比如model的值映射到一个格式化的字符串),视图控制器本身就会不再臃肿。当你开始使用MVVM的最好方式是,可以先将一小部分逻辑放入视图模型,然后当你逐渐习惯于使用这个范式的时候再迁移更多的逻辑到视图模型中。

使用MVVM的iOS app是高度可测试的;因为view model包含了所有的展示逻辑并且不会引用view,所以它可以通过编程方式充分测试。虽然有众多的hack技术参与到测试Core Data模型,但使用MVVM写的app可以进行充分的单元测试。

以我的经验,使用MVVM会轻微的增加代码量,但总体上减少了代码的复杂性。这是一个划算的交易。

MVC与MVVM之间在IOS中的区别的更多相关文章

  1. 一文解读MVC/MVP/MVVM (转)

    这篇文章对目前 GUI 应用中的 MVC.MVP 和 MVVM 架构模式进行详细地介绍. MVC 在整个 GUI 编程领域,MVC 已经拥有将近 50 年的历史了.早在几十年前,Smalltalk-7 ...

  2. IOS的MVC和MVVM模式简明介绍

    iOS中的MVC(Model-View-Controller)将软件系统分为Model.View.Controller三部分,结构图如下: Model: 你的应用本质上是什么(但不是它的展示方式) C ...

  3. iOS学习之MVC,MVVM,MVP模式优缺点

    为什么要关注架构设计? 因为假如你不关心架构,那么总有一天,需要在同一个庞大的类中调试若干复杂的事情,你会发现在这样的条件下,根本不可能在这个类中快速的找到以及有效的修改任何bug.当然,把这样的一个 ...

  4. iOS 关于MVC和MVVM设计模式的那些事

    一.概述 在 iOS 开发中,MVC(Model View Controller)是构建iOS App的标准模式,是苹果推荐的一个用来组织代码的权威范式.Apple甚至是这么说的.在MVC下,所有的对 ...

  5. iOS开发——高级篇——iOS中常见的设计模式(MVC/单例/委托/观察者)

    关于设计模式这个问题,在网上也找过一些资料,下面是我自己总结的,分享给大家 如果你刚接触设计模式,我们有好消息告诉你!首先,多亏了Cocoa的构建方式,你已经使用了许多的设计模式以及被鼓励的最佳实践. ...

  6. iOS中MVC等设计模式详解

    iOS中MVC等设计模式详解 在iOS编程,利用设计模式可以大大提高你的开发效率,虽然在编写代码之初你需要花费较大时间把各种业务逻辑封装起来.(事实证明这是值得的!) 模型-视图-控制器(MVC)设计 ...

  7. 浅析前端开发中的 MVC/MVP/MVVM 模式

    MVC,MVP和MVVM都是常见的软件架构设计模式(Architectural Pattern),它通过分离关注点来改进代码的组织方式.不同于设计模式(Design Pattern),只是为了解决一类 ...

  8. iOS中的MVC

      我们今天谈谈cocoa程序设计中的 模型-视图-控制器(MVC)范型.我们将从两大方面来讨论MVC: 什么是MVC? M.V.C之间的交流方式是什么样子的? 理解了MVC的概念,对cocoa程序开 ...

  9. 写给iOS小白的MVVM教程(一): 从MVC到MVVM之一个典型的MVC应用场景

    前言 本着实践为主的原则,此系列文章不做过多的概念性的阐述和讨论;更多的代码和篇幅用来展示MVC和MVVC下的基础代码结构与具体实现,来展示各自优劣.这篇文章,更多的在于发掘MVC与MVVC的共性,以 ...

随机推荐

  1. Web开发须知的浏览器内幕 缓存与存储篇(1)

    本文禁止转载,由UC浏览器内部出品. 0.前言 大纲 浏览器缓存和存储相关的功能分为四类: 加载流程 Memory Cache Application Cache(简称AppCache) HTTP C ...

  2. 淘宝 NPM 镜像

    使用说明 : 更多见  https://npm.taobao.org 你可以使用我们定制的 cnpm (gzip 压缩支持) 命令行工具代替默认的 npm: $ npm install -g cnpm ...

  3. CountDownTimer的用法及原理

    1.主线程中使用 值得注意的是,CountDownTimer可以在主线程中直接使用.验证一下回调的执行线程.在主线程中执行如下代码 CountDownTimer countDownTimer = , ...

  4. String和StringBuffer有什么区别

    首先,String和StringBuffer主要有2个区别: (1)String类对象为不可变对象,一旦你修改了String对象的值,隐性重新创建了一个新的对象,释放原String对象,StringB ...

  5. C#字节流通信格式

    类似通信格式的实现关键点: byte数组转float的实现,BitConvetor.toSingle() float类型转by,BitConverter.GetBytes #客户端发送public b ...

  6. Jmeter入门(一)————线程组配置

    线程组相当于有多个用户,同时去执行相同的一批次任务.每个线程之间都是隔离的,互不影响的.一个线程的执行过程中,操作的变量,不会影响其他线程的变量值. Delay Thread creation unt ...

  7. 对于大型公司项目平台选择j2ee的几层认识

    我是一个从野路子上一路走来的程序员,现在主要用.net做方案.选.net不选jave并没有什么特别的原因,只不过是因为我自己从c,java学起,后来被vs这个工具所吸引, 很熟悉这个平台罢了,从业15 ...

  8. PHP中的trait方法冲突

    laravel使用中我们可能需要对User model使用softdelete这个功能,以便删除后还可以恢复,不幸的是entrust模块也有这个方法,两者产生冲突, 解决办法: https://lar ...

  9. 远程桌面到 Ubuntu 虚拟机

    安装 Ubuntu 虚拟机,创建端口号为 3389 的 Endpoint. 安装 Gnome 桌面 复制 sudo apt-get update sudo apt-get install ubuntu ...

  10. The associated COM server does not support ActiveX Document embedding

    winfrom 通过dsoframer实现读取excel文件报错: System.Reflection.TargetInvocationException: Exception has been th ...