它不是一个控制器,它是一个视图控制器。这在类名中要么是显式的(UIViewController、UITableViewController)要么是隐式的(UITabBarController,因为 UITabBar 是一个视图;UINavigationController,因为导航是一个范例;而 UINavigationController 有一个非常薄的视图)。
我能想到的唯一非视图“控制器”是 NSFetchedResultsContoller。
但为什么会有奇怪的设计?
其中一部分与 iPhone UI 范例有关:用户一次与一个屏幕交互。如果“全屏”不可见,则可以回收其大部分内存。 UIViewControllers 代表一个屏幕并管理屏幕如何与其他屏幕交互。
(当然,Apple 在 iPad 上稍微扩展了这一点以实现弹出框/拆分视图,但两者仍然是有效的“全屏”而不是通用视图。视图控制器与桌面操作系统上的窗口大致相似,除了大多数它们大部分时间都不可见。)
其中一部分与 CoreAnimation 有关:UIView 处理绘图/布局并由 CALayers 支持。 CALayers 有效地表示 GPU 上的纹理多边形; “图层内容”(即纹理)不能任意卸载以释放内存。 (我不完全确定为什么,但这意味着您可以将内容设置为 CGImage 一次,然后不理会它。)由于许多视图的属性都由图层属性(框架、边界、中心、内容拉伸、.. .),让视图存在而没有图层有点愚蠢。最终结果是视图是重量级的,并且它们偶尔需要在内存不足时消失,因此视图控制器需要跟踪应该在视图卸载/重新加载期间持续存在的事物(滚动位置、当前选定的项目……)。是的,它可以要求视图对自身进行序列化,但是序列化是icky,而且大多数东西都不需要序列化。
其中一部分与惰性有关:您需要实现视图控制器来处理它与其他视图控制器的交互方式。另一方面,视图会自动调整大小——如果您乐于在 nib 或 -viewDidLoad 中设置布局,则通常不需要编写自定义视图。懒惰决定了你不这样做,所以布局经常发生在视图控制器中。
就我个人而言,当它似乎更有意义时,我会实施一个“智能”视图。以天气应用程序为例:当视图加载时,您必须在每个单元格中显示几天的天气(可能是也可能不是表格视图单元格;没关系)。当您获得更新时,您必须更新所有单元格。您可以实现 -[WeatherViewController updateCell:],但似乎更有意义的是只拥有 -[WeatherCell setWeather:] 并将其传递给您的模型。视图控制器中的混乱少了很多。
我还归咎于懒惰和可维护性:有时将所有内容都放在一个文件中更容易,而有时拥有具有次要专业化的半重复代码比编写支持其所有用例的通用视图更容易。它比 Enterprise Java 好得多,在 Enterprise Java 中,通常有一个函数调用一个函数调用一个函数调用一个函数(function-of-a-singleton-that's-instantiated -with-a-factory-with-some-class-that-you-need-to-track-down)-that-calls-a-function-that-calls-a-function 找出企业软件正在使用可以用 1 行 Python 表示的密码哈希算法。 (我只是稍微夸大了一点。)
(那么当您决定天气单元的总体布局适合显示月相/能见度时会发生什么?将通用的东西移到超类并创建一个 AstronomerCell 或其他什么。)
另外,如果您的视图不能与模拟控制器一起工作,那么您做错了。视图不应该知道它们的视图控制器;视图控制器应该将自己注册为动作目标(我认为是 addAction:target:forControlEvents:)或适当的委托。他们都不希望目标是视图控制器。