拆开Massive View Controller

在每个项目的某个时刻,设计师都会坐在您的办公桌旁,询问您将屏幕移动到流程中其他位置的难度。 也许您的同事无所适从,问为什么您的Sweet View Controller会知道每个其他View Controller。 或您的经理突然来询问您为什么没有任何测试。

所有合理的问题。 您的脸(如图所示:😬)比您以前说的更多。 这将比他们想象的要多得多

一个相当典型的iOS应用程序体系结构涉及创建视图控制器,这些视图控制器决定下一个要呈现的视图控制器以及应如何呈现它们。 他们还负责启动网络请求,解释响应,更新模型并调解子视图或子视图控制器之间的通信。

mega-view-controller做很多事情:

  1. 获取有关其呈现方式的上下文。
  2. 处理用户交互,启动计算,更新结果。
  3. 确定接下来要显示的屏幕。
  4. 配置下一个视图控制器。
  5. 在某个地方展示下一个视图控制器。 它会进入导航控制器吗? 哪一个? 它是模态的吗? 这样的细节不太可能通过通常狭窄的API表面公开-通常,没有超出UIViewController呈现的东西。

结果,这段代码充满了隐式依赖。 这很难测试,甚至更难重新排列。

这个想法很简单:隔离您的视图控制器- 他们不需要知道哪个屏幕在前或下一屏幕

在这种模式下, 视图控制器的工作是控制视图,布局和动画。 流量控制器的工作是代表一个特定的状态机并遍历该状态机。 当需要进行状态转换时(例如,网络请求,流程中的前进或后退等),视图控制器将通过委派或阻止回调将其推迟回流程控制器。 这样,可以在不实例化所有支持基础结构的情况下测试视图控制器。

啊哈! 现在可以测试视图控制器了! 它不再依赖于之前发生的事情,也不知道接下来会发生什么-它与表示样式无关。 现在可以轻松地在流内或流之间移动视图控制器。

如果那是您的事,那么流量控制器本身也很容易测试。 甚至公开一些基本细节,例如当前显示的屏幕以及调用代表动作以模拟在流程中的遍历,都会带您到达那里。 毕竟这只是一台状态机。

在这种模式下,视图控制器应该做的尽可能少。 逻辑应仅限于将数据提供者连接到子视图,管理动画以及响应用户事件。 还有更多应该委托出去。

步骤1使View Controller委派所有操作

接下来是Flow对象。 这充当所有托管视图控制器的委托,并负责呈现和配置它们。

步骤2设计由您的View Controller组成的流程

这就是全部。 这种设计模式使隐式依赖关系的网络反转,有利于委派和显式依赖关系注入。 准备测试时,构造视图控制器,遵守委托协议并练习公共API。

当然,大多数项目要复杂得多-这就是这种模式的真正体现。 现在不仅可以在流之间重复使用视图控制器,还可以轻松地从其他流中构建聚合流。

很疯狂的东西,是吗?

我汇集了一个非常简单的基于这些概念的Master / Detail应用程序,欢迎您查看这些概念,我很喜欢您的想法!

martinmroz / Medium-FlowControllerDemo

Medium-FlowControllerDemo –来自流控制器和您的演示:拆解单片视图控制器

github.com