MVC
简介
MVC,全称是 Model View Controller,是模型 (model)-视图 (view)-控制器 (controller) 的缩写。
现在,MVC 已经成为主流的客户端编程框架,在 iOS 开发中,系统为我们实现好了公共的视图类:UIView
,和控制器类:UIViewController
。大多数时候,我们都需要继承这些类来实现我们的程序逻辑,因此,我们几乎逃避不开 MVC 这种设计模式。
从上图可以看出,MVC的本质是将Model和View进行隔离
问题
- Controller很难复用
- 大量代码都集中在 Controller 之中,让 MVC 模式变成了 Massive View Controller 模式。
Controller 的核心工作
- 在初始化时,构造相应的 View 和 Model。
- 监听 Model 层的事件,将 Model 层的数据传递到 View 层。
- 监听 View 层的事件,并且将 View 层的事件转发到 Model 层。
Controller的本质是一个调度者,逻辑部分应该分离出去,从而达到瘦身的目的
MVVM
简介
MVVM 是 Model-View-ViewModel 的简写。
将View和Controller合并来实现界面,分离出逻辑和数据部分,形成新的架构。从而达到让难复用的Controller瘦身的目的
MVVM 在使用当中,通常还会利用双向绑定技术,使得 Model 变化时,ViewModel 会自动更新,而 ViewModel 变化时,View 也会自动变化。所以,MVVM 模式有些时候又被称作:model-view-binder 模式。
具体在 iOS 中,可以使用 KVO 或 Notification 技术达到这种效果。
问题
- 数据绑定使得 Bug 很难被调试。你看到界面异常了,有可能是你 View 的代码有 Bug,也可能是 Model 的代码有问题。数据绑定使得一个位置的 Bug 被快速传递到别的位置,要定位原始出问题的地方就变得不那么容易了。
- 对于过大的项目,数据绑定需要花费更多的内存。
希望的做法
想法
采用MVVM的思想给Controller瘦身,但不引入ReactiveCocoa
- 基于输入( Signal)的处理方式和主流iOS开发方式差距太大
- 双线绑定技术带来的学习成本和额外复杂度,调试困难
做法
- 增加ViewModel,完成显示逻辑;
- 增加Logic辅助类,完成数据获取、转换等业务逻辑;
- 将网络、数据库等独立出来
三层开发模式
界面层开发
- 用Storyboard完成主流程
- 用xib制作可复用的View
- 用代码方式构建动态的View
- 用ViewModel实现显示逻辑
- 用Logic辅助类(NSObject为基类)完成交互
- 数据用demo数据
- 逻辑直接给结果
- 能够定义出调用接口就好
- 用Controller调度ViewModel和Logic,实现设计
- 每个Controller都配上至少一个ViewModel和Logic;Controller本身只做调度的事情,保持简单
- 尽量轻,不要涉及数据处理和业务逻辑
- 和UI/UE协作开发,及时响应,及时修改,按照demo开发模式来做
- 关键是快,并及时得到产品、运营等干系人的认可与支持
- 按照页面组织结构分模块
- ViewModel设计成struct(swift)
- 大量采用以UIView、UIViewController为基类的成员
- 以NSObject为基类的成员实现下沉到逻辑层
数据层开发
- 让界面层先行,让需求更明确,可以延迟一个Sprint
- 后台根据界面层的成果进行API文档定义
- 尽量轻,面向API编程,只完成数据的传输,不做逻辑处理
- 跟后台密切协作,尽量快,及时修改
- 按照数据方式进行分模块,比如HTTPS, DataBase, KeyChain等等
- 做成framework,方便调用,可以参考第三方库的实践,比如Alamofire
- 不能出现以UIView、UIViewController为基类的成员
逻辑层开发
- 让数据层先行,让接口更明确,可以延迟一个Sprint
- 完成数据层的数据和界面层展示的转换
- 完成各种业务逻辑
- 添加各种额外功能,比如统计,监控等等
- 按照业务和功能划分模块
- 用framework的方式进行封装
- 考虑代码复用
- 不能出现以UIView、UIViewController为基类的成员
不同层中的Model
- 界面层 === ViewModel === 所有字段都不能为nil,全部提供默认值
- 逻辑层 === Model === 部分字段可以为nil,部分提供默认值
- 数据层 === Bean === 所有字段都可以为nil,不提供默认值