View 的最大的任务就是向 Controller 传递用户动做事件。
ViewController 再也不承担一切代理和数据源的职责,一般只负责一些分发和取消网络请求以及一些其余的任务。
1.1 苹果推荐的 MVC -- 愿景
- Cocoa MVC
-
- 因为 Controller 是一个介于 View 和 Model 之间的协调器,因此 View 和 Model 之间没有任何直接的联系。Controller 是一个最小可重用单元,这对咱们来讲是一个好消息,由于咱们总要找一个地方来写逻辑复杂度较高的代码,而这些代码又不适合放在 Model 中。
- 理论上来说,这种模式看起来很是直观,但你有没有感到哪里有一丝诡异?你甚至据说过,有人将 MVC 的缩写展开成 (Massive View Controller),更有甚者,为 View controller 减负也成为 iOS 开发者面临的一个重要话题。若是苹果继承而且对 MVC 模式有一些进展,全部这些为何还会发生?
1.2 苹果推荐的 MVC -- 事实
- Realistic Cocoa MVC
-
- Cocoa 的 MVC 模式驱令人们写出臃肿的视图控制器,由于它们常常被混杂到 View 的生命周期中,所以很难说 View 和 ViewController 是分离的。尽管仍能够将业务逻辑和数据转换到 Model,可是大多数状况下当须要为 View 减负的时候咱们却无能为力了,View 的最大的任务就是向 Controller 传递用户动做事件。ViewController 再也不承担一切代理和数据源的职责,一般只负责一些分发和取消网络请求以及一些其余的任务。
- 你可能会看见过不少次这样的代码:
BookModel *bookModel = [myDataArray objectAtIndex:indexPath.row];
[cell configWithModel:bookModel];
-
- 这个 cell,正是由 View 直接来调用 Model,因此事实上 MVC 的原则已经违背了,可是这种状况是一直发生的甚至于人们不以为这里有哪些不对。若是严格遵照 MVC 的话,你会把对 cell 的设置放在 Controller 中,不向 View 传递一个 Model 对象,这样就会大大减小 Controller 的体积。Cocoa 的 MVC 被写成 Massive View Controller 是不无道理的。
- 直到进行单元测试的时候才会发现问题愈来愈明显。由于你的 ViewController 和 View 是紧密耦合的,对它们进行测试就显得很艰难--你得有足够的创造性来模拟 View 和它们的生命周期,在以这样的方式来写 View Controller 的同时,业务逻辑的代码也逐渐被分散到 View 的布局代码中去。
1.3 MVC 自身的不足
- MVC 是一个用来组织代码的权威范式,也是构建 iOS App 的标准模式。Apple 甚至是这么说的。在 MVC 下,全部的对象被归类为一个 model,一个 view,或一个 controller。Model 持有数据,View 显示与用户交互的界面,而 View Controller 调解 Model 和 View 之间的交互。然而,随着模块的迭代咱们愈来愈发现 MVC 自身存在着不少不足。
- 1)MVC 在现实应用中的不足:
-
- 在 MVC 模式中 view 将用户交互通知给控制器。view 的控制器经过更新 Model 来反应状态的改变。Model(一般使用 Key-Value-Observation)通知控制器来更新他们负责的 view。大多数 iOS 应用程序的代码使用这种方式来组织。
- 2)愈发笨重的 Controller:
-
- 在传统的 app 中模型数据通常都很简单,不涉及到复杂的业务数据逻辑处理,客户端开发受限于它自身运行的的平台终端,这一点注定使移动端不像 PC 前端那样可以处理大量的复杂的业务场景。然而随着移动平台的各类深刻,咱们不得不考虑这个问题。传统的 Model 数据大多来源于网络数据,拿到网络数据后客户端要作的事情就是将数据直接按照顺序画在界面上。随着业务的愈来愈来的深刻,咱们依赖的 service 服务可能在大多时间没法第一时间知足客户端须要的数据需求,移动端愈发的要自行处理一部分逻辑计算操做。这个时间一惯的作法是在控制器中处理,最终致使了控制器成了垃圾箱,愈来愈不可维护。
- 控制器 Controller 是 app 的 “胶水代码”,协调模型和视图之间的全部交互。控制器负责管理他们所拥有的视图的视图层次结构,还要响应视图的 loading、appearing、disappearing 等等,同时每每也会充满咱们不肯暴露的 Model 的模型逻辑以及不肯暴露给视图的业务逻辑。这引出了第一个关于 MVC 的问题...
- 视图 view 一般是 UIKit 控件(component,这里根据习惯译为控件)或者编码定义的 UIKit 控件的集合。进入 .xib 或者 Storyboard 会发现一个 app、Button、Label 都是由这些可视化的和可交互的控件组成。View 不该该直接引用 Model,而且仅仅经过 IBAction 事件引用 controller。业务逻辑很明显不纳入 view,视图自己没有任何业务。
- 厚重的 View Controller 因为大量的代码被放进 viewcontroller,致使他们变的至关臃肿。在 iOS 中有的 view controller 里绵延成千上万行代码的事并非前所未见的。这些超重 app 的突出状况包括:厚重的 View Controller 很难维护(因为其庞大的规模);包含几十个属性,使他们的状态难以管理;遵循许多协议(protocol),致使协议的响应代码和 controller 的逻辑代码混淆在一块儿。
- 厚重的 view controller 很难测试,不论是手动测试或是使用单元测试,由于有太多可能的状态。将代码分解成更小的多个模块一般是件好事。
- 3)太过于轻量级的 Model:
-
- 早期的 Model 层,其实就是若是数据有几个属性,就定义几个属性,ARC 普及之后咱们在 Model 层的实现文件中基本上看不到代码(无需再手动管理释放变量,Model 既没有复杂的业务处理,也没有对象的构造,基本上 .m 文件中的代码广泛是空的);同时与控制器的代码越来厚重造成强烈的反差,这一度让人不由对现有的开发设计构思有所怀疑。
- 4)遗失的网络逻辑:
-
- 苹果使用的 MVC 的定义是这么说的:全部的对象均可以被归类为一个 Model,一个 view,或是一个控制器。就这些,那么把网络代码放哪里?和一个 API 通讯的代码应该放在哪儿?
- 你可能试着把它放在 Model 对象里,可是也会很棘手,由于网络调用应该使用异步,这样若是一个网络请求比持有它的 Model 生命周期更长,事情将变的复杂。显然也不该该把网络代码放在 view 里,所以只剩下控制器了。这一样是个坏主意,由于这加重了厚重控制器的问题。那么应该放在那里呢?显然 MVC 的 3 大组件根本没有适合放这些代码的地方。
- 5)较差的可测试性
-
- MVC 的另外一个大问题是,它不鼓励开发人员编写单元测试。因为控制器混合了视图处理逻辑和业务逻辑,分离这些成分的单元测试成了一个艰巨的任务。大多数人选择忽略这个任务,那就是不作任何测试。
- 上文提到了控制器能够管理视图的层次结构;控制器有一个 “view” 属性,而且能够经过 IBOutlet 访问视图的任何子视图。当有不少 outlet 时这样作不易于扩展,在某种意义上,最好不要使用子视图控制器(child view controller)来帮助管理子视图。在这里有多个模糊的标准,彷佛没有人能彻底达成一致。貌似不管如何,view 和对应的 controller 都牢牢的耦合在一块儿,总之,仍是会把它们当成一个组件来对待。Apple 提供的这个组件一度以来在某种程度误导了大多初学者,初学者将全部的视图所有拖到 xib 中,链接大量的 IBoutLet 输出口属性,都是一些列问题。