组合UIView创建复杂视图的最佳方法是什么?

9
从 Web-stack 转向 iOS 的世界,我发现很难理解如何为 MVC 重新构思思路,并有效地在 iOS 上构建我的 UI。
前提:
在 Web-stack 中: - Controller 通常对应 URL,而 View 则代表页面。 - View 可以通过 CSS、Javascript 和片段等方式避免重复代码。
在 iOS 中: - 进入新屏幕后,该屏幕对应一个 UIViewController。 - 我们有一个 UIView,这个 UIView 包含自己的 UIViews。 - UIView 与 UIViews 并存,UIViewController 也可以与 UIViews 并存。 - 我们一定要将繁重的逻辑或数据处理委托给最近的控制器。 - 在 iOS 中,感觉大多数情况都是 “View first”,这非常棒。
问题:
将视图组合到我的 self.view 中的最佳方法是什么? - 将视图作为 UIView 类 - 视图作为带有关联 UIView 类的 UIViewController - 视图作为具有内联 UIView 的 UIViewController 示例视图层次结构:
------------------------------
|             A              |
|                            |
|    --------------------    |
|    |        B         |    |
|    |                  |    |
|    |  --------------  |    |
|    |  |     C      |  |    |
|    |  |            |  |    |
|    |  |            |  |    |
|    |  |            |  |    |
|    |  |            |  |    |
|    |  |            |  |    |
|    |  |            |  |    |
|    |  --------------  |    |
|    |                  |    |
|    --------------------    |
|                            |
------------------------------

[具体细节] 我的不舒服经历:

  • A 可能会 [self addView:B_view] (如果 B 只是 UIView)
  • A 也可能会 [self addView:B_viewController.view] (如果 B 有一个视图控制器)
  • A 还可能会 [B setChildView:C_view]
  • 我们可以有 B_viewController.delegate = A & C_viewController.delegate = A
  • 我们还可以有 B_viewController.delegate = A & C_view.delegate = B
  • 在所有这些情况共存的情况下,我们必须考虑范围
  • 我看到通过长委托链回答了 A 的 C 的担忧。

逻辑分散在代理、视图控制器和视图之间

分离关注点——但是如何?

除了"抽象良好和关注点分离"这个论点可以改善以上经验。我认为它们很容易造成视图控制器和视图控制器.视图的出血,从而导致广泛的耦合。

这很快变得混乱,感觉像意大利面条,尽管努力控制也很难。

话虽如此,

  • 有哪些最佳实践可以解决以上问题?
  • 有哪些绝对不要做的事情?
  • 在很难提出好的论点时,我们如何避免长委托链,因为当有委托时,它有效地表示你可以更好地处理这个问题?

这个问题来自实际经验,我相信不仅仅是我,应该会成为一个很好的资源。 - Yugal Jindle
2
好问题,不明白为什么会被踩。虽然我自己也常问这个问题,但不确定我能否回答。 - deadbeef
2
好问题。楼主已经做了功课并且把问题结构化得很好。请添加一个下投票的理由。 - jerrymouse
1
如果这被标记为“过于宽泛”,那么在 Stack 网站上询问此类问题的位置是什么? - Bista
1
由于您所询问的是与应用程序架构相关的问题,我建议您阅读以下关于iOS应用程序架构的文章:https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52#.gjp0yrwkn - KrishnaCA
4个回答

3
也许,你正在处理的是MVC - Massive View Controllers困境。这里有一篇有趣的文章,Marcus在其中谈到通过将代码放置在其应该属于的地方(网络层,持久化层或理想情况下的视图控制器)来有效地管理代码。

http://www.cimgf.com/2015/09/21/massive-view-controllers/

除了委托模式外,我们还有基于块/闭包的方法,可以帮助清理代码。

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html

一般来说,Robert C. Martin的"代码整洁之道"方法可能会有所帮助。通过一种名为VIPER架构的东西来实现它。以下是相关教程。

https://www.objc.io/issues/13-architecture/viper/

作为一种语言,Objective C采用委托模式,并且在大多数情况下使用它是标准做法。
欢迎来到iOS平台。

3

我曾试图在stackoverflow上提出类似广泛的问题,但看起来社区更喜欢更具体的技术问题。但我会尝试一下。请记住,以下所有内容都是我的个人意见,而不是硬性规则。

我觉得这是一个关于消息传递和设计模式的复合问题。在组件通信方面(无论是视图还是控制器),有许多方法可以进行,每种方法都有其优点和缺点(或者说用例)。有:委托、响应链、块、通知、反应信号等等。

简而言之

  • 我的个人偏好肯定是尽可能使视图保持简单,并将业务逻辑放在其他地方(取决于您选择的模式),以实现更好的组合。
  • 您的直觉与我的相符:无论何时您的组件(视图或视图控制器)正在执行self.superviewself.parentViewController(有些人甚至说self.navigationController),它可能会违反封装性并且有更好的方法。
  • 长委托链肯定是个问题。有时它们很容易遵循,有时不是,但这不是世界上最糟糕的事情,尽管很可能有更好的方法来处理通信。

以下是一些随机观察结果,可能会让你有所收获(也可能不会)。

MVC是iOS快速而简单的方式

在我看来,MVC模式对于小项目来说非常适用(从“易于”与“简单性”比较中可见)。但从个人经验来看,当您正在工作的屏幕复杂度增加时,MVC很快就无法掌控。控制器倾向于处理从用户交互到网络的所有内容,很快就变成了一只1k长的怪物。

不幸的是,在iOS架构中很多东西都依赖于UIViewController。它往往成为您的代码与操作系统接触的第一个接触点,但它不必在内部处理所有内容。相反,它可以将责任路由到适当的组件,例如:

func loginButtonDidTap(_ sender: UIButton) {
  loginManager.beginLogin(from: self)
  analytics.reportLogin(with: sender)
  // ...
}

也可以组合控制器

从您的描述中我没有完全注意到,但如果您喜欢使用MVC,组合控制器是完全有效的选项。在构建iPad时,这是非常常见的情况,但即使在iPhone上,每个屏幕都可以轻松包含完全独立的部分,其中每个部分都是一个单独的ViewController,然后您应该了解所谓的“UIViewController容器”。它主要允许更好的分离和重用,但同样并不能解决主要问题。

一定要探索其他模式

如果您正在阅读本文,则非常渴望学习。在这种情况下,我建议不要停留在MVC上。有许多有趣的设计模式可能适用于您的特定需求,也可能不适用。MVVM曾经很受欢迎。最近,单向流似乎成为新的热门事物。受JS的Redux启发。它与MVC非常不同,如果您感兴趣,建议查看此项目https://github.com/ReSwift/ReSwift

遗憾的是,像任何架构问题一样,没有对和错 - 只有适合您和您的团队或不适合您的事情。在问题被关闭为“过于宽泛”之前,我很想听到其他观点。

如果这完全不是您要求的,请告诉我是否有任何特定方面需要讨论。


1
  • 您可以有一个ViewController

  • 将UIView分离到ViewController中。它不应该与viewController紧密耦合。

  • 让您的View在UIView类本身中登录。创建自己的委托和协议,并在任何视图控制器中使用它。

  • 将viewcontroller添加到viewcontroller不是一个好的解决方案。

  • 您也可以转移到MVVM,其中每个视图都将在其视图模型中具有其逻辑部分,但在开始时可能会令人困惑。

  • 尝试将UIView分离到ViewControllers中。


1
作为一个做过相当数量的iOS编程并现在花费大量时间进行angular开发的人,这里有一些快速想法: UIView代表了基本的屏幕构建块;也就是说,它包括视图、一些数据以及渲染该数据的逻辑。因此,它可以用于绘制一些文本或图形,或者它可以包含任意数量具有相同能力的子视图。在Angular世界中,UIView会(在某种程度上)等同于封装了HTMLCSSJavaScript等内容的Component,但也可以包含其他组件。
正如你所知,iOS提供了许多预先构建的本地UIView - UILabelUIButtonUITable等,这些都适用于大部分应用程序需求。
一个UIViewController的功能比UIView更加结构化。它与导航框架集成,以便开发人员可以快速为用户更改上下文。它包含一个“主”UIView,作为上下文的基本平台,包含任意数量的本地和自定义的UIView。其目的是帮助配置这些UIViews,考虑到当前应用程序上下文。
如果UIViewController正在以不限于当前应用程序上下文的方式配置UIView,那么UIView可能应该扩展为自定义对象。这样它就可以自我管理,并且更容易在其他上下文中重用。
还有一件事:
当适用时,委托非常好,但NSNotification是一种简单而强大的方法,可以观察变化,同时避免对象依赖的混乱。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接