iOS开发工程师,大部分时间要和界面打交道,由于苹果的框架已经为我们提供了最基础的mvc的设计模式,许多时候我们只是机械的添加着一个有一个的view controller, add 一个又一个的subView,那么我们能不能从这些细节中脱身出来,到一个更高的层次来总结我们的iOS前端开发模式呢,本文对常见的MVC设计模式及其变种进行了总结。
一. 主动mvc
“主动—MVC”模式,也是通常意义下的MVC模式
何为主动?View不是等Controller通知它Model更新了然后才从Model取数据并更新显示,而是自己监视Model的更新(如果用观察者模式)或主动询问Model是否更新。前面那种等待Controller通知的方式是下面所介绍的“被动—MVC”的实现方式。】
二. 被动mvc(基本等同mvp)
1)Model 和 View 永远不能相互通信,只能通过 Controller 传递。
2)Controller 可以直接与 Model 对话(读写调用 Model),Model 通过 Notification 和 KVO 机制与 Controller 间接通信。
3)Controller 可以直接与 View 对话,通过 outlet,直接操作 View,outlet 直接对应到 View 中的控件,View 通过 action 向 Controller 报告事件的发生(如用户 Touch 我了)。Controller 是 View 的直接数据源(数据很可能是 Controller 从 Model 中取得并经过加工了)。Controller 是 View 的代理(delegate),以同步 View 与 Controller。
三. 苹果推荐的mvc
苹果想要的的mvc和传统mvc类似,是这样:
但是,由于苹果的贴心,每个vc都自带一个view,所以苹果的mvc变成这样:
那么,问题来了,这样的模式导致的最重要问题:
model太轻,controller太重, 最后过于臃肿无法控制,且无法进行测试。 MVC 变成 Massive View Controller。
四. Controller瘦身
根据唐巧的博客总结,C端瘦身可以抽象成下面几个方法:
1. 将网络请求抽象到单独的类中
新手写代码,直接就在 Controller 里面用 AFNetworking 发一个请求,请求的完数据直接就传递给 View。入门一些的同学,知道把这些请求代码移到另外一个静态类里面。但是我觉得还不够,所以我建议将每一个网络请求直接封装成类。
把每一个网络请求封装成对象其实是使用了设计模式中的 Command 模式,它有以下好处:
- 将网络请求与具体的第三方库依赖隔离,方便以后更换底层的网络库。
- 方便在基类中处理公共逻辑,例如猿题库的数据版本号信息就统一在基类中处理。
- 方便在基类中处理缓存逻辑,以及其它一些公共逻辑。
- 方便做对象的持久化。
2.将界面的拼装抽象到专门的类中
新手写代码,喜欢在 Controller 中把一个个 UILabel ,UIButton,UITextField 往 self.view 上用 addSubView 方法放。我建议大家可以用两种办法把这些代码从 Controller 中剥离。
方法一:构造专门的 UIView 的子类,来负责这些控件的拼装。这是最彻底和优雅的方式,不过稍微麻烦一些的是,你需要把这些控件的事件回调先接管,再都一一暴露回 Controller。
方法二:用一个静态的 Util 类,帮助你做 UIView 的拼装工作。这种方式稍微做得不太彻底,但是比较简单。
对于一些能复用的 UI 控件,我建议用方法一。如果项目工程比较复杂,我也建议用方法一。如果项目太紧,另外相关项目的代码量也不多,可以尝试方法二。
3.构造 ViewModel
这其实就是MVVM。具体做法就是将 ViewController 给 View 传递数据这个过程,抽象成构造 ViewModel 的过程。
这样抽象之后,View 只接受 ViewModel,而 Controller 只需要传递 ViewModel 这么一行代码。而另外构造 ViewModel 的过程,我们就可以移动到另外的类中了。
4.专门构造存储类
刚刚说到 ViewModel 的构造可以抽奖到一个 Service 层。与此相应的,数据的存储也应该由专门的对象来做。
数据存取放在专门的类中,就可以针对存取做额外的事情了。比如:
- 对一些热点数据增加缓存
- 处理数据迁移相关的逻辑
- 如果要做得更细,可以把存储引擎再抽象出一层。这样你就可以方便地切换存储的底层,例如从 sqlite 切换到 key-value 的存储引擎等。
五. MVVM
MVVM其实是MVVMC, 其实就是构造了一个充血数据模型,并将充血的部分从Controller中划到了ViewModel中,其模型如下:
View <-> C <-> ViewModel <->Model
比如一个最简单的Name类,从服务端拿到两个属性firstName与lastName,但是界面上需要展示的是fullName,这个时候可以构造一个VM类,可以通过Name类的firstName yu lastName来组装fullName。 当然这是最简单的一个例子,但基本就是类似的意思。
MVVM 在使用当中,通常还会利用双向绑定技术,使得 Model 变化时,ViewModel 会自动更新,而 ViewModel 变化时,View 也会自动变化。所以,MVVM 模式有些时候又被称作:model-view-binder 模式。
具体在 iOS 中,可以使用 KVO 或 Notification 技术达到这种效果。或者使用ReactiveCocoa。