现代MVC

当iPhone仅是第三部时,我在Apple Developer门户上有关iOS编程的第一篇教程的开头看到了此图:

(仍然存在类似的文章,并且图表在那里:Cocoa核心能力。模型-视图-控制器)

该图展示了基本的iOS体系结构模式MVC 。 10年前,我以一种非常简单的方式理解了该图: UIView,UIScrollView或UITableView是该上的视图 。 作为开发人员,我将它们安排在Interface Builder中的一个场景上,并将它们与我的源代码(在视图控制器中定义的出口动作)绑定在一起。 最后一个正是MVC图中的控制器 。 我的应用程序将用户数据存储在例如文本文件中,或者在更复杂的情况下通过Core Data存储。 图表中的模型是允许访问此数据的类。

要添加的另一件事: 模型中没有业务逻辑代码,该模型不与视图通信。 视图控制器负责创建所有视图模型,并在它们之间进行通信。

这样简单的系统的行为很明显:用户与视图进行交互,并且他的动作被传递给视图控制器。 最后一个执行计算,更改其自己的状态,并且此状态反映在视图中。 如果用户操作需要更改模型 ,则视图控制器会调用该模型进行更改。 如果模型发生更改,则会将该更改通知给视图控制器 。 视图控制器就是其中之一,它可以更新视图

这是对这种基本模式的简化甚至天真的理解。 但是它允许开发简单的应用程序,例如计算器或绘画工具。 我想展示一种开发和维护更复杂的应用程序的方法。

首先,让我们变换上面的图并以分层样式绘制它。

它使人想起大学时代熟悉的常见应用程序架构图:

该层是一个非常时髦的术语。 分层样式无处不在,包括应用程序体系结构。 我当时的所有项目都从该图开始,具有三个应用程序层:用户界面,业务逻辑和数据。 所有应用程序对象都属于这些层之一。 数据层和用户界面不进行通信,而是通过业务逻辑进行通信。

让我们复杂化该分层MVC图。 View-controller创建模型并在发生更改时调用它,并在图中显示为箭头。 箭头从视图控制器视图视图控制器创建所有视图 ,并在其状态或模型发生更改时对其进行更新。 该模型视图控制器一无所知,如果模型发生更改,它会发布有关该视图的通知,或者更常见的是, 视图控制器会观察到模型更改。 它在运行时发生,我更喜欢使用虚线从模型视图控制器绘制此箭头。

虚线箭头还应该显示从视图视图控制器的连接 :用户在运行时与视图进行交互,但是视图不直接调用视图控制器视图不知道视图控制器界面并通过Target-Action Design模式将用户操作传递给视图控制器

这是MVC的最简单或理想形式,适用于仅由一个视图控制器构造的小型应用程序。 让我们再添加一个view-controller

例如,单击视图控制器中的按钮(上面带有一个视图 控制器的原始架构)将打开一个新的视图控制器 :原始视图控制器包含一个动作方法,我将在其中创建和初始化另一个视图- controller ,它创建自己的视图模型并对其进行管理。

上的视图控制器之间有两个连接箭头:

  • 原始视图控制器创建并初始化辅助视图控制器
  • 辅助视图控制器将数据(用户输入或操作)传输到第一个视图控制器代表设计模式。 这种数据转换发生在运行时,因此由虚线绘制。

假设中的第二个视图控制器包含一个特殊功能,该功能可以从Internet下载图片或数据文件:

该应用程序本身很简单:两个视图控制器和一个下载功能。 该图也不难。 但这显示了视图控制器之间的紧密联系。 图上还可以看到另一件事–第二个视图控制器内部具有特殊的服务功能。 您可以想象整个源代码的样子:原始视图控制器文件开头的#import行很少,有一个代码初始化了第二个视图控制器 ,第二个视图控制器有一个方法下载一个图像。
我可以建议使用其他特殊服务方法添加更多视图控制器 ,但即使现在您仍然看到意大利面条代码-无法测试,无法维护。

我有多少个项目正是以这种方式使用MVC? 我制作的演示很少,原型很少,概念验证很少,…—目的是测试某些东西,演示一些东西,而且我也不会发布它,我从来没有计划维护这些项目。

如何处理一个真正的使用寿命长的AppStore项目?
什么是商业项目的现代建筑?

我从最简单的问题开始,使用两个视图控制器来重构该应用程序:将图像下载方法移至一个单独的类,例如DownloadController 。 在视图控制器中,我添加了一个DownloadController类型的变量,并且在发生图像下载的位置,我将其称为新控制器。 这是众所周知的构图设计模式。 该代码更加解耦并且更可重用:

让我们进行第三步-返回DownloadController并使其继承一个协议,该协议声明一个将下载图像的函数。 让我们在需要时在协调器中创建DownloadController的实例,并将其传递给第二个view-controller 。 最后一个将不依赖于DownloadController类,而是依赖于此Download协议。

此图是否比上面带有两个视图控制器和下载过程的图更复杂? 大概。 但是该项目的源代码更干净,更可维护,可重用和可测试。

带有协调器的 Modal-View-Controller以及其他一些著名的设计模式,例如CompositionDependency Injection,可以开发现代复杂的应用程序,并避免Massive View-Controller综合征。

参考文献:

  1. 马丁·福勒(Martin Fowler)。 应用控制器
  2. 苹果开发人员库。 可可核心能力
  3. 马特·加拉格尔(Matt Gallagher)。 看可可中的模型视图控制器
  4. Soroush Khanlou。 8种模式可帮助您摧毁Massive View Controller