一. MVC的概念
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,注意它是一种框架模式,而不是设计框架。
二. MVC的优点
MVC设计模式是用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
三. Cocoa MVC元素
iOS中Model模型是封装应用程序的数据模型对象,并定义操控和处理该数据的逻辑和运算。
View视图对象是应用程序中用户可以看到的对象。视图对象的主要目的就是显示来自应用程序模型对象的数据,并使该数据可被编辑。在iOS开发中所有的控件,窗口都继承自UIView,UIView及其子类主要负责UI的实现,而UIView所产生的事件都可以采用委托的方式,交给UIViewController实现。
Controller控制器对象是应用程序的一个或者多个视图对象和一个或者多个模型对象之间的媒介。通过它视图了解模型对象的改变,反之亦然。控制器对象还可以为应用程序执行和协调任务,并管理其他对象的生命周期。对不同的UIView有相应的UIViewController,对应MVC中的C。
四. Cocoa MVC的主要特点
Controller是核心:Controller可以和View和Model主动通信。
View是界面元素,分为两部分来理解:一是界面元素需要的数据部分,二是界面自身状态的变化阶段。
View的功能就是显示界面元素不做逻辑处理,故View没有必要改变Model数据。故此不可以和Model通信.
-
View通过点击事件,进行人机交互,因此View可以和Controller直接通信,通信方式为以下几种:
4-1. 通过动作-目标模式,即Action,把View中的某个动作通过消息的方式映射到Controller上,实现通信(黄色箭头,红色箭靶),即View是Controller的一个属性,因此通过Action,控制器可以控制其他属性。
4-2. 通过Delegate代理模式,把界面自身状态的变化,如didxxx,willxxx,shouldxxx等,通过消息的方式映射到Controller上,实现通信(黄色长线带有多箭头),如View把Action封装,虽然是Controller属性,但是Controller不能直接添加逻辑处理,因此需要实现Delegate协议,或者不同Controller的交互也需要使用Delegate。
4-3. 通过DataSource的模式,把界面自身数据的状态和变化,如Count,Data等,通过消息的方式映射到Controller上,实现通信(黄色长线带有多箭头),最经典的就是常见的UITableView类。
虽然我们也可以通过KVO或者Notification的方式使View的某些消息定制投射到Controller上,但是并不主张如此,因为这就是将一部分处理逻辑放到了View里,这对MVC结构来说,是一个破坏。只是如果确实是必要的话,也是可以考虑使用的。
Model是数据模型,初学者很容易把Model和Controller混在一起,而不把他们独立开来编写代码。为了更容易的重用和修改,建议还是独立出来比较好,这也是MVC结构的本质。
Model不可以和View直接通信(黄色双实线)。
Model一般不会和Controller直接通信,在和Controller的关系中,Model是处于被动通信的地位,Controller可以直接和Model通信,而Model往往通过KVO机制和Notification的方式把自身的变化投射给Controller(Model的黄色发射塔,Controller的黄色接收塔)。
五. Cocoa MVC的内部功能实现
View:
- 布局UI:就是将需要展示的界面显示到手机上。
- 监听点击事件:通过动作-目标模式,Delegate代理模式让控制器来处理逻辑。
- 实现DataSource:将模型数据注入到View中,以显示View。
Model:
- 实现数据的格式化。
- 利用Notification || KVO构造方法,和Controller通信,监听数据的变化。
Controller:
- 因为控制器本身有一个View属性,因此Controller需要做View的事情。
- 将SubView添加到Controller的View上。
- 实现SubView Action || Delegate协议,监听事件&&实现DataSource以展示SubView。
- 进行原始数据的加载:如应用HTTP协议加载后台数据,将原始数据注入到数据模型。
六. Cocoa MVC的弊端
Controller和View耦合严重,导致Controller和View都很难做单元测试。
有很多不知道该放在哪的代码放在Controller,导致Controller过于臃肿,基本无法复用。
七. 针对重ViewController的瘦身方式
- 将UITableView的DataSource分离到另一个类中。
- 将数据获取和转换的逻辑分离到另一个类中。
- 将拼装控件的逻辑,分离到另一个类中。
- 将网络请求抽象到单独的类中。
- 构建ViewModel。
- 专门构造存储类。
参考资料:
iOS MVC框架模式
被误解的 MVC 和被神化的 MVVM
iOS 架构模式 - 简述 MVC, MVP, MVVM 和 VIPER (译)