用Model-View-ViewModel构建iOS App(转)
转载自 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构建iOS App(转)的更多相关文章
- 用Model-View-ViewModel构建iOS App
如果你已经开发一段时间的iOS应用,你一定听说过Model-View-Controller,即MVC.MVC是构建iOS App的标准模式.然而,最近我已经越来越厌倦MVC的一些缺点.在本文,我将重温 ...
- ios app开发步骤
虽然开发一个app的任务看上去可能很艰巨,但是整个过程可以抽象成几个相对简单的步骤,下面这些步骤会在你开发第一个app时帮你步入正途. 定义Concept 每个好app都是从一个concept开始. ...
- 用Xamarin和Visual Studio编写iOS App
一说开发 iOS app,你立马就会想到苹果的开发语言 Objective C/Swift 和 Xcode.但是,这并不是唯一的选择,我们完全可以使用别的语言和框架. 一种主流的替换方案是 Xamar ...
- 【IOS笔记】Using View Controllers in Your App
参考:http://www.cnblogs.com/patientAndPersist/p/3279645.html Using View Controllers in Your App Whethe ...
- 关于报错:'sharedApplication' is unavailable: not available on iOS (App Extension) - Use view controller based
最近在看Extension相关知识的时候,自己写了个小demo 发现[UIApplication sharedApplication]这个方法敲不出来了, 总是报错:'sharedApplicatio ...
- iOS9中找不到XXX.dylib 与 is unavailable no availabel on ios (app extension) - use view controller 的解决办法
在 iOS9 中现在找不到 XXX.dylib 了,比如libz.tbd 如果要用到 libz.dylib,可以用下面的办法,来自 Stack Overflow. Go to Build Phase ...
- iOS App开发的那些事儿2:如何搭建合适的框架
<iOS App开发的那些事儿>系列文章从更宏观的角度出发,不仅仅局限于具体某个功能.界面的实现,而是结合网易云信iOS端研发负责人多年的经验,从如何优化现有代码的角度出发,深度分析如何创 ...
- iOS App开发那些事:如何选择合适的人、规范和框架?
http://www.cocoachina.com/ios/20141202/10386.html 自从做Team Leader之后,身上权责发生了变化,于是让我烦恼的不再是具体某个功能,某个界面的实 ...
- Qt Model/View(官方翻译,图文并茂)
http://doc.trolltech.com/main-snapshot/model-view-programming.html 介绍 Qt 4推出了一组新的item view类,它们使用mode ...
随机推荐
- 如何在VS 2010中使用 VS2013的解决方案(转)
今天要用VS2010打开VS2013,一直觉得VS2010到VS2012只是界面上扁平化的改变,平台工具集有改变但很大程度上可能向上兼容.在网上搜了一些文章,其中有一篇说到一个观点: 从 ...
- 【前端优化之拆分CSS】前端三剑客的分分合合
几年前,我们这样写前端代码: <div id="el" style="......" onclick="......">测试&l ...
- Atitit.软件兼容性原理与实践 v5 qa2.docx
Atitit.软件兼容性原理与实践 v5 qa2.docx 1. Keyword2 2. 提升兼容性的原则2 2.1. What 与how 分离2 2.2. 老人老办法,新人新办法,只新增,少修改 ...
- 中国式商业智能报表ActiveReports免费公开课,10月20日开讲
ActiveReports公开课全方位报表解决方案,满足商业报表五大需求 [开课时间]10月20日[主讲老师]葡萄城报表产品经理[开课形式]网络在线公开课[活动费用]前50名免费 适合人群:报表开发人 ...
- mysql操作入门基础之对数据库和表的增删改查
一.数据库管理-- 1.登陆数据库 mysql -u root -p; -- 2.查看数据库服务器所有数据库 SHOW DATABASES; -- 3.创建数据库 CREATE DATABASE My ...
- SSH面试题(struts2+Spring+hibernate)
struts2 + Spring +hibernate Hibernate工作原理及为什么要用? 原理: 1.读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory ...
- Linux 6.5(oracle 11.2.0.4)单实例ASM安装
Linux 6.5(oracle 11.2.0.4) 1.解析主机.配置网络等 /etc/hosts /etc/sysconfig/network /etc/init.d/NetworkManager ...
- 关于Redis的ACID
事务是一个数据库必备的元素,对于redis也不例外,对于一个传统的关系型数据库来说,数据库事务满足ACID四个特性: A代表原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全 ...
- VS2015 出现 .NETSystem.Runtime.Remoting.RemotingException: TCP 错误
错误内容: 界面显示内容为: .NET�������������System.Runtime.Remoting.RemotingException: TCP 淇¢亾鍗忚鍐茬獊: 搴斾负鎶ュご銆� 鍦 ...
- mdadm设定RAID磁盘阵列,且当分区故障后如何重建
首先,fdisk建立不同分区,且设为fd格式 其次, mdadm -C md0 -a yes -l -n /dev/sda1 /dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sd ...