在 iOS 中,每个 UIView 都应该有一个 UIViewController 吗?

Posted

技术标签:

【中文标题】在 iOS 中,每个 UIView 都应该有一个 UIViewController 吗?【英文标题】:In iOS, should every UIView have a UIViewController? 【发布时间】:2015-10-18 03:30:20 【问题描述】:

许多视图都有子视图,它们不一定需要有自己的控制器与之关联。在 Apple 的 own tutorial 创建自定义视图中,他们实际上并没有为每个子视图创建一个子 UIViewController。

但是,我经常遇到这样的情况,即我会有一个视图层次结构,其中子视图的某些子视图有一个发送网络请求的按钮。在那种情况下,我可以做一个目标:

myView.addTarget(self, action: "networkRequest:", forControlEvents: UIControlEvents.TouchDown)

然后在同一个 myView 类中我可以处理该网络请求,但这似乎打破了 MVC 模式。视图不应该做逻辑,它们应该只显示东西,对吗?


另一个选项我们可以做的是让每个视图都可以访问其逻辑所需的父级或祖父级控制器。在这种情况下,我的目标可能类似于:

func networkRequest(view : MyView) 
    self.controller.doNetworkRequest()

但这似乎也不是一个正确的解决方案。再一次,我们似乎只是在打破 MVC 并摆脱困境。


因此,据我所知,我们只剩下两个选项之一:

首先,我们可以从父控制器本身添加目标和所有逻辑。但是这样做会给我们带来像这样的讨厌的链条:

self.grandParentView.parentView.childView.addTarget(self, action: "networkRequest:", forControlEvents: UIControlEvents.TouchDown)

那长长的访问列表让我不寒而栗,而且看起来很糟糕。但是,它似乎仍然遵循 MVC。从技术上讲,我们正在控制器中执行逻辑,对吗?


但可能还有另一种选择。我们可以只给每个视图一个控制器,并让每个 UIViewController 为每个新的子视图都有一个子控制器。

但是,有些视图是静态的。它们实际上没有任何逻辑,因此它们不一定需要控制器。但是,如果我们要遵循这个约定,我们基本上每个视图都需要一个,否则我们会在控制器有孙控制器但没有子控制器的情况下出现不一致。

所以我们需要为我们的控制器创建很多空棺材。这会构建许多从未使用过的死代码,这可能会导致一些软件腐烂。


那么比我更聪明更聪明的人,这里的正确解决方案是什么?

【问题讨论】:

""不,但每个视图都应该是视图控制器的主视图,或者应该是此类视图的子视图(在一定深度)。 您仍然会遇到上述问题。你会得到冗长的层次结构链。 也许你会。我不。在任何时候都不必有超过 一个 视图控制器。你只是在想这整件事。 【参考方案1】:

可能有比我更聪明的 MVC 大师,但我会试一试:

选项 1 - 失败

如果您在 UIView 子类中处理网络请求,那么您肯定会破坏 MVC 模式。根据 Apple 的 MVC 参考:

视图对象是应用程序中用户可以看到的对象。视图对象知道如何绘制自己并且可以响应用户操作。

看起来,视图应该简单地处理用户可以看到和与之交互的内容。不要不要走这条路。

选项 2 - 成功

让我们回到 Apple 对视图控制器的 MVC 参考:

控制器对象充当应用程序的一个或多个视图对象与其一个或多个模型对象之间的中介。因此,控制器对象是一个管道,视图对象通过它了解模型对象的变化,反之亦然。控制器对象还可以为应用程序执行设置和协调任务,并管理其他对象的生命周期。

请注意文档如何说“一个或多个”,因为视图控制器处理多个视图的物流是完全可以接受的。就个人而言,我会说,如果您的视图只有一个按钮需要委托来处理网络请求,请继续将父视图的视图控制器设置为委托。

当视图的数据处理变得“复杂”时,您应该让视图拥有自己的视图控制器,为简洁起见,我将其定义为“会混淆父视图的视图控制器的明显目的的多个操作。”

话虽如此,可以在视图控制器中用#pragma mark 清楚地标记代码在哪里,所以请在此处使用您的判断。

选项 3 - 呃……

给每个视图一个自己的视图控制器绝对是可行的,但你真的认为有必要吗?每次你需要处理一个按钮点击时都创建一个全新的视图控制器,如果应用程序是可扩展的,这肯定看起来有点矫枉过正。

总结

选择选项 #2 并使用您的最佳判断。你不会因为违反 MVC 模式而受到惩罚。最糟糕的是,如果您的视图逻辑变得复杂,您会将代码重构为新的视图控制器。

更多参考:

Model-View-Controller - ios Developer Library

希望这会有所帮助!

【讨论】:

【参考方案2】:

首先,很好地提出了问题!

回答您的问题 - 不,每个 UIView 都没有必要拥有一个视图控制器来管理它们,但行业明智的最佳实践是自行卸载 UIView 管理 - MVC 设计模式。

我建议使用委托。它可以很好地保持 MVC 模式不变并使自定义 UIView 可重用。

我有很多自定义 UIView,我在多个视图控制器中使用它们。我处理它们的方式是:

    创建一个协议并在其中添加必要的方法。 让视图控制器符合该协议。 实施必要的协议方法。 在UIView 中处理 UI 操作触发器,并将处理传递给委托人。

【讨论】:

【参考方案3】:

让我们从基础开始……视图应该是愚蠢的。

如果您曾经编写过具有应用程序逻辑、业务逻辑或引用模型对象的视图,那么您做错了。

注意:这包括表格视图单元格和集合视图单元格!!

你有问题的正确答案。

首先,我们可以从父控制器本身添加目标和所有逻辑。

但是,你有一个顾虑。

但是这样做会给我们带来讨厌的锁链

实际上,这应该不是问题。保持您的自定义视图平坦。您应该始终能够保持最多 1 级视图间接(视图属性是第二级间接)。

myView.mySubview
myView.mySubview.myProperty

为此,我尝试遵循一些基本规则。

    保持视图简单。 继承优于组合以添加新功能。 当所有其他方法都失败时,使用容器视图(这就是您应该如何看待子视图控制器)。

【讨论】:

以上是关于在 iOS 中,每个 UIView 都应该有一个 UIViewController 吗?的主要内容,如果未能解决你的问题,请参考以下文章

从 nib 文件加载 UIView?

iOS - UIView 不显示在 UIStackView 内

UIView 作为轮播的项目

UIView (或 UILabel ?)与情节提要中另一个 View 的链接

UIView中的iOS UIScrollView

iOS:在调用 view.hidden = NO 之后,有没有办法确定 UIView 何时出现