ReactiveCocoa & MVVM 学习总结二

二. MVVM
1. 什么是MVVM

MVVM是指 Model-View-viewmodel的简称,与MVC的一个主要区别是 view 拥有view model。这个与MVC不一样,MVC中应该是controller拥有view。同时,view model 中应该不包含相关view的代码,这样以来,view model就是独立的,可以与任何view进行绑定。

A view model is like an adapter for the model that makes it suitable for presentation. The view model is also where presentation behavior goes.



MVVM是微软提出的,基于MVC的一种设计模式,更准确来说是基于Martin Fowlers Presentation Model ( http://martinfowler.com/eaaDev/PresentationModel.html)。在MVVM中,与MVC一样也是有3个组件,但是与MVC还是有区别的。在MVVM中,我们倾向于把ViewController和View放在一个整体中,把他们当做MVVM的View组件。与MVC最主要的不同之处在于,我们引入了View Model,View Model会通过observer的方式把更新推送到View组件中,一般来说observer是通过RAC来实现的。在MVVM中,View Model封装了用于View绑定的数据/属性和一些验证逻辑以及操作。


在MVVM中,the view 和 view controller正式连接在一起被作为一个整体来对待,View。View仍然不会持有model,他们会持有view model。view model可以做很多事情,比如验证用户数据的逻辑,view的展示逻辑,发出网络请求,以及其他各种操作。但是view model有一件事不能做,不能持有任何对view的引用,总之,view model要做到在iOS和OS X都能直接被使用(换句话说,不能 #import UIKit.h)。
当你看到上图时,你会发现我只是使用了两个比较含糊的动词 “notify” 和 “update”,但是并没有说明如何去实现。尽管可以像MVC中那样使用KVO来实现,但是很快你就会发现这样会使代码变得不可控。因此,在实际中,我们最好使用ReactiveCocoa把MVVM中各个部分组合在一起。

在我自己看来,View Model主要是用来获取data(如网络请求读取数据库等),对data进行操作(如验证转换格式等),以及控制用于View绑定的数据和属性,总之,就是各种逻辑操作都可以放到这里处理,最终要做到的就是把数据变为可展示的格式,用于UI进行填充。注意,不要有与UIView相关的代码

2. MVVM的优势
1) View models are testable. (脱离UI之后,测试起来会非常简单方便,之前MVC中那些比如展示效果之类的测试也很容易就可以做到,而且UI的更改不会影响测试case的开发)
2) View models can be used like models. (这里主要的意思是,view model的操作更加简单,比如可以进行copy和序列化操作,这个用来做类似恢复UI非常有用途)
3) View models are (mostly) platform-agnostic. (大部分情况下,甚至可以做到平台无关,比如跨iPhone/iPad/Mac)
4) Views and view controllers are simpler. (把逻辑放到view model之后,view/view controller就会变得很简洁清晰)

3. 在MVVM中View Controller的职责
绑定View与View Model,响应View Model,调用View Model相应的方法,负责View和window的转换,布局UI,动画,设备旋转,展示UI

1) view-model 作为view controller的一个属性存在,view controller 了解 view-model和它的public属性,但是view-model对view controller却一无所知。
2) view-model 应该只暴露尽可能少的信息给view controller,view controller也根本不需要关心view-model是如何获取数据的,view-model可以通过网络或者验证或者计算或者之前已经存在的数据,这些对view controller都是透明的,它只关心他需要的必须的那些数据。
3) 不必使用一个view-model来负责屏幕上所有的数据,可以使用child view-models来负责那些很小并且容易封装的区域的数据。这在那种有view重用机制(例如 table view cell)的地方非常有用。而对于那些不是可复用的view,则没有必要使用child view-models,只需要把view-model直接传递给那个view即可,这种方式还有一种额外的好处,就可以让所有的subviews的更新保持同步,由于他们绑定了同一个view-model,只要view-model中对应的属性发生变化,所有的subviews都会被update。注: 这个也是我之前很困惑的地方,在做之前公司的项目时,我就曾经遇到类似的问题,当时的解决方式是自己实现了一套KVO机制,不过问题也很明显,就是耦合很重,同时内存处理上也很麻烦。

5. https://github.com/ReactiveCocoa/ReactiveViewModel,这个开源项目默认提供了一个RVMviewmodel来作为view model的基类,但是我一直很困惑这个类的用途。参考了一下ash的书,他主要是用RVMviewmodel中的active属性来表示view model是否处于激活状态,避免在view model init的时候发起网络请求,而是在view model处于active的时候才发起:


但是这种用法,感觉不是很优雅,使用RACCommand去实现的话,可以比这个要优雅很多,可以参考, http://codeblog.shape.dk/blog/2013/12/05/reactivecocoa-essentials-understanding-and-using-raccommand/,这篇文章里的思想以及我之前的博客中的介绍和github上的demo。网友Sam lau也给我提供了一个他写的小项目作为参考,对学习RAC非常有好处, https://github.com/samlaudev/DesignerNewsForObjc

参考资料:

相关文章

导入moment 使用方式 年月日,时分秒 星期几 相对时间 7天后 2小时后 明天 将毫秒转换成年月日
@ 一、前言 为什么介绍redux-actions呢? 第一次见到主要是接手公司原有的项目,发现有之前的大佬在处理...
十大React Hook库 原文地址:https://dev.to/bornfightcompany/top-10-react-hook-libraries-4065 原文...
React生命周期 React的生命周期从广义上分为挂载、渲染、卸载三个阶段,在React的整个生命周期中提供很...
React虚拟DOM的理解 Virtual DOM是一棵以JavaScript对象作为基础的树,每一个节点可以将其称为VNode,用...
React中JSX的理解 JSX是快速生成react元素的一种语法,实际是React.createElement(component, props, ....