Model-View-ViewModel for iOS [译]
如果你已经开发一段时间的iOS应用,你一定听说过Model-View-Controller, 即MVC。MVC是构建iOS app的标准模式。然而,最近我已经越来越厌倦MVC的一些缺点。在本文,我将重温一下MVC是什么,详述它的缺点,并且告诉你一个新的方式来架构你的app:Model-View-ViewModel。拿出你的流行语bingo card(宾果卡,一种游戏卡片-译者注),因为我们即将进行一次范式转变。
Model-View-Controller
Model-View-Controller是一个用来组织代码的权威范式。Apple甚至是这么说的。在MVC下,所有的对象被归类为一个model,一个view,或一个controller。Model持有数据,View显示与用户交互的界面,而view controller调解model和view之间的交互。
在上图中,view将用户交互通知给controller。view controller通过更新model来反应状态的改变。model(通常使用Key-Value-Observation)通知controller来更新他们负责的view。大多数iOS应用程序的代码使用这种方式来组织。
模型model的对象通常非常非常的简单。很多时候,他们就是Core Data managed objects,或者避免使用Core Data,就是其他流行的数据模型层。根据Apple的文档,model包括数据和操作数据的业务逻辑。在实践中,model层往往非常薄,不管怎样,model层的业务逻辑被拖入了controller。
视图view通常是UIKit控件(component,这里根据习惯译为控件)或者编码定义的UIKit控件的集合。进入.xib或者Storyboard会发现一个app、Button、Label都是由这些可视化的和可交互的控件组成。你懂的。View不应该直接引用model,并且仅仅通过IBAction事件引用controller。业务逻辑很明显不归入view,视图本身没有任何业务。
还有控制器controller。Controller是app的“胶水代码”:协调模型和视图之间的所有交互。控制器负责管理他们所拥有的视图的视图层次结构,还要响应视图的loading、appearing、disappearing等等,同时往往也会充满我们不愿暴露的model的模型逻辑以及不愿暴露给视图的业务逻辑。这引出了第一个关于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会轻微的增加代码量,但总体上减少了代码的复杂性。这是一个划算的交易。
回过头再来看MVVM的图示,你会注意到我使用了模糊的动词“notify”和“update”,而没有详细说明该怎么做。你可以使用KVO,就像MVC那样,但这很快就会变得难以管理。事实上,使用ReactiveCocoa会是更好的方式来组织各个部分。
关于怎么结合ReactiveCocoa来使用MVVM的信息,可以阅读Colin Wheeler的excellent write-up或者看看我写的开源app。你也可以阅读我的关于ReactiveCocoa和MVVM的书.
原文链接
Model-View-ViewModel for iOS by Ash Furrow
延伸阅读
- an-introduction-to-mvvm-and-reactivecocoa-on-ios
- Reactive-Cocoa-Tutorial
- mvvm-tutorial-with-reactivecocoa-part-1
- deep-into-reactivecocoa2
- ReactiveCocoa
Model-View-ViewModel for iOS [译]的更多相关文章
- Qt:Drag-Drop操作在QGraphicsView及Model/View框架下的实现
最近使用到Qt的Drag Drop功能,结合自己的例子写下来给大家分享一下.实现从QTreeView拖动Node到QGraphicsView上,以及QGraphicsView上item之间的拖动. 先 ...
- Qt Model/View(官方翻译,图文并茂)
http://doc.trolltech.com/main-snapshot/model-view-programming.html 介绍 Qt 4推出了一组新的item view类,它们使用mode ...
- MVC模式(Model View Controller)下实现数据库的连接,对数据的删,查操作
MVC模式(Model View Controller): Model:DAO模型 View:JSP 在页面上填写java代码实现显示 Controller:Servlet 重定向和请求的转发: 若 ...
- (转)Qt Model/View 学习笔记 (七)——Delegate类
Qt Model/View 学习笔记 (七) Delegate 类 概念 与MVC模式不同,model/view结构没有用于与用户交互的完全独立的组件.一般来讲, view负责把数据展示 给用户,也 ...
- (转)Qt Model/View 学习笔记 (六)——在views中选择数据项
在views中选择数据项 概念 用于新的view类中的选择模型比Qt3中的模型有了很大的改进.它为基于model/view架构的选择提供了更为全面的描述.尽管对提供了的views来说,负责操纵选择的标 ...
- (转)Qt Model/View 学习笔记 (五)——View 类
Qt Model/View 学习笔记 (五) View 类 概念 在model/view架构中,view从model中获得数据项然后显示给用户.数据显示的方式不必与model提供的表示方式相同,可以与 ...
- (转)Qt Model/View 学习笔记 (四)——创建新的Models
创建新的Models 介绍 model/view组件之间功能的分离,允许创建model利用现成的views.这也可以使用标准的功能 图形用户接口组件像QListView,QTableView和QTre ...
- (转)Qt Model/View 学习笔记 (三)——Model类
Model类 基本概念 在model/view构架中,model为view和delegates使用数据提供了标准接口.在Qt中,标准接口QAbstractItemModel类中被定义.不管数据在底层以 ...
- (转)Qt Model/View 学习笔记 (二)——Qt Model/View模式举例
Qt Model/View模式举例 Qt提供了两个标准的models:QStandardItemModel和QDirModel.QStandardItemModel是一个多用途的model,可用于表示 ...
随机推荐
- Java 内部类的阐述
创建一个Computer抽象类:用来在Test类中创建匿名抽象类 package com.zhiyou; public abstract class Computer { int a = 1; /** ...
- 基于Ruby的watir-webdriver自动化测试方案与实施(五)
接着基于Ruby的watir-webdriver自动化测试方案与实施(四) http://www.cnblogs.com/Javame/p/4164570.html 继续 ... ... 关于特殊控件 ...
- java入门知识点结构
第一部分 计算机程序和面向对象编程 编程语言种类: 机器语言:2进制(0和1) 汇编语言:英文字符缩写和助记符 高级语言: 面向过程:面向过程是从微观上/细节上处理具体事务. C语言 面向对象: ...
- 编写Javascript类库(jQuery版) - 进阶者系列 - 学习者系列文章
这些年主要关注于项目管理方面的工作,编码就比较少了.这几天比较空闲,就想把原来的经验沉淀下来,一个是做好记录,以后如果忘记了还能尽快找回来,第二个是写写博文,算是练练手笔吧. 言归正传,这次写的是Ja ...
- Linux(RHEL6.0)下安装GCC
查看系统版本 [root@CP-RHEL proc]# cat /etc/issue Red Hat Enterprise Linux Server release 6.0 (Santiago) Ke ...
- 全新的membership框架Asp.net Identity(1)——.Net membership的历史
在Asp.net上,微软的membershop框架经历了Asp.net membership到Asp.net simple membership,再到现在的Asp.net Identity. 每一次改 ...
- [翻译]——SQL Server使用链接服务器的5个性能杀手
前言: 本文是对博客http://www.dbnewsfeed.com/2012/09/08/5-performance-killers-when-working-with-linked-server ...
- Linux 如何查看修改DNS配置
DNS服务器介绍 DNS是计算机域名系统(Domain Name System 或Domain Name Service) 的缩写,它是由域名解析器和域名服务器组成的.域名服务器是指保存有该网络中所有 ...
- MSDB数据库置疑的解决方法
1.原因 机房停电,服务器非法关机,导致MSDB数据库被“置疑” 2.Msdb数据库的作用 Msdb 数据库供SQLServer 代理程序调度警报和作业以及记录操作员时使用.比如,我们备份了一个数据库 ...
- mysql的DATE_FORMAT用法
DATE_FORMAT(date,format) date 参数是合法的日期.format 规定日期/时间的输出格式. mysql的DATE_FORMAT用法 %a 缩写星期名 %b 缩写月名 %c ...