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

时间:2016-11-05 00:08:43

标签: ios cocoa-touch uiview uiviewcontroller

从网络堆栈过渡到 iOS仙境,我发现很难理解如何重新构建我对MVC的想法并在iOS上有效地构建我的UI

前提:

  • 在网络堆栈中:
    • Controller通常对应一个URL,而view代表页面。
    • 视图有办法不用CSS + Javascript +片段重复代码。
  • 在iOS中:
    • 进入与UIViewController对应的新屏幕。
    • 我们有一个组成自己的UIViews的UIView
    • UIViews存在于UIViews,UIViewController与UIViews,UIViewController与内联UIViews
    • 我们绝对会将重型或数据逻辑委托给最近的控制器
    • 在iOS中感觉非常感觉首先

问题:

考虑使用以下内容构建我的self.view视图的最佳方式是什么?

  • UIView
  • 的视图
  • UIViewController形式发布的视图,其关联的UIView类。
  • UIViewController
  • 为内嵌的UIView视图

示例视图层次结构:

------------------------------
|             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的问题。

逻辑分散在委托,viewControllers和视图

分离问题 - 但如何?

除了可以改善以上经验的“抽象井和关注点分离”。我相信它的viewController和viewController.view的组合很容易引起广泛的耦合。

这很快变得令人困惑,感觉就像意大利面,尽管付出了努力但很难控制。

那就是说,

  • 解决上述陷阱的最佳做法是什么?
  • 绝对不应该做什么?
  • 我们如何避免长代表链很难提出好的论据,因为委托有效地说你可以更好地处理这个问题?

4 个答案:

答案 0 :(得分:3)

我没有在stackoverflow上提出类似的广泛问题 - 似乎社区偏爱更具体的技术问题。但我会试一试。请记住,以下所有内容都是我的意见,而不是硬性规定。

我觉得这是关于消息传递和设计模式的复合问题。在组件通信方面(无论是视图还是控制器),有很多方法可以实现,每个方法都有+-(或者更确切地说是用例)。有:委托,响应链,块,通知,反应信号 - 仅举几例。

TL; DR

  • 我个人的偏好绝对是让视图尽可能简单,并将业务逻辑放在其他地方(取决于您选择的模式),以便更好地合成。
  • 你的直觉与我的一致:每当你的组件(视图或视图控制器)正在执行self.superviewself.parentViewController(有人说甚至是self.navigationController)时,它可能违反了封装,并且有一个更好的方式。
  • 长代表连锁店肯定是个问题。有时它们很容易被追随,有时却不容易,但它并不是世界上最糟糕的事情,尽管有可能有更好的方式来处理沟通。

以下几项随机观察可能会导致您某处(或可能不会)。

MVC是一种快速(和肮脏)的方式来吸引人们在iOS

在我看来,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

可悲的是,任何建筑问题都没有对错 - 只有对你和你的团队有用的东西才有用。而且我喜欢在问题被关闭之前听到其他观点,因为太宽泛了#34;

很抱歉,如果这完全不符合您的要求,请告诉我您是否有任何特殊方面需要讨论。

答案 1 :(得分:3)

也许,你正在处理的是MVC - 大规模视图控制器的困境。这是一个有趣的读物,Marcus谈到通过将代码放在它所属的地方,网络层,持久层或表示层(理想情况下是viewcontroller)来有效地管理代码。

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/

目标C,作为一种语言包含授权模式,并且将其用于大多数人的关注是一种标准做法。

欢迎使用iOS平台。

答案 2 :(得分:1)

  • 您可以拥有一个ViewController

  • 将UIViews分隔为ViewController。它不应该与viewController紧密结合。

  • 让您的View登录自己的UIView类。创建自己的委托和协议。并在任何viewcontroller中使用它。

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

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

  • 尝试将UIViews分隔为ViewControllers。

答案 3 :(得分:1)

作为一个已经完成了相当数量的iOS编程并且现在花费大量时间进行角度开发的人,这里有一些简单的想法:

UIView代表基本的屏幕构建块;也就是说,它会破坏视图,某些数据以及在视图上呈现该数据的逻辑。因此,它可以用于绘制一些文本或图形,或者它可以包含任意数量的具有相同能力的子视图。在Angular世界中,UIView将(某种程度上)等同于封装ComponentHTMLCSS等的JavaScript,但也可能包含UILabel其他组件。

如您所知,iOS提供了许多预构建的本机UIView,UIButtonUITableUIViewController等,这些适用于大量应用程序需要。

UIView具有比UIView更多的结构功能。它与导航框架集成,以便开发人员可以快速更改用户的上下文。它包含一个" main" UIView's,作为上下文的基础平台,包含任意数量的本机和自定义UIViews。其目的是在给定当前应用程序上下文的情况下帮助配置UIViewController

如果UIView正在以不限于当前应用上下文的方式配置UIView,那么NSNotification可能应该扩展为自定义对象。这样它就可以自我管理,并且更容易在其他环境中重用。

另一件事:

代表在适当的时候很棒,但if [[ ! $value =~ ^\$ ]]; 是一种简单,强大的方法来观察变化,同时避免对象依赖的意外。