【问题标题】:Discuss on MVC implementation on iPhone讨论 iPhone 上的 MVC 实现
【发布时间】:2010-10-02 13:34:43
【问题描述】:

我在不同的框架上使用了一段时间的 MVC 模式,例如 (swing, android, gwt ...) 现在,我正在学习 iPhone 框架,我对 MVC 的实现感到非常惊讶。我要问的是关于视图和控制器交互的问题。

首先,这就是我构想 MVC 模式的方式:

  • 视图和控制器通过接口相互通信(一个用于视图,另一个用于控制器)

  • 在我的 MVC 模式概念中,控制器不必知道视图的属性。 (例如,控制器不能有视图的标签属性实例,但可以通过视图接口的方法要求视图更改此标签的值)

不让控制器直接作用于视图 UI 元素的优点是耦合度低,因此可以更轻松地测试视图。该视图可以在隔离(或使用模拟控制器)的情况下启动和测试。

关键是,在 iPhone 上,控制器(例如 ViewController)直接知道 UI 元素,因此我不理解。 我的目标不是批评我刚刚学习的框架。但如果这真的像我描述的那样有效,我觉得那不是很干净......

有没有人对这个框架进行过更多的实验,可以给我详细信息/解释?或者,如果您不同意我的 MVC 方法,请告诉我 ;)

此外,我问的是我的方法是否比 MVC 更接近 MVP(在此处描述:http://code.google.com/intl/fr/webtoolkit/articles/testing_methodologies_using_gwt.html)。

【问题讨论】:

  • 这是一个很好的问题。老实说,我更喜欢将视图和控制器分开
  • here 中的一个很好的解释。我想这会对你有所帮助。

标签: iphone model-view-controller mvp


【解决方案1】:

自从first formalized in Smalltalk 之后,MVC 的含义就不同了,而且 MVC 的 NeXTSTEP (Cocoa) 版本与 Smalltalk 的并不完全匹配。 Smalltalk的分解基本是这样的:

  • 模型保存数据
  • 视图呈现数据
  • 控制器管理用户交互

NeXTSTEP 的分解实际上更像这样:

  • 模型保存数据
  • 视图绘制数据
  • 控制器管理“逻辑”(包括绘图数据的“表示”部分)

我在这里区分绘图和呈现,因为 NSView 对数据的“含义”往往很愚蠢。它只专注于绘制像素。因此,您倾向于将实际字符串传递给它,而不是视图撕裂并“呈现”的对象。

这不是一个巨大的差异,但它是你遇到的事情的原因。 IMO 的主要转变是,使用 Cocoa/NeXTSTEP,视图类变得越来越可重用。为了变得如此可重用,更多对应用程序敏感的部分需要移出到控制器中。我认为这通常是一个好处,因为它会导致更少的子类、更易理解的代码和更多可重用的代码......大多数时候。特别是,它允许您更轻松地交换执行更精美绘图的视图(以特定方式为动画或在行等上交替颜色的视图),而不会碰到通常存在于控制器中的任何特定于应用程序的逻辑。

也就是说,当视图特别复杂时,我确实发现创建更专业的视图来获取数据对象并管理它们自己的表示是有益的,我相信你所设想的方式更多。

编辑:还有一点需要注意。 Apple 的示例代码在设计方面通常很糟糕。它们几乎从不包含模型类,并且将几乎所有可以想象到的东西都塞进 ViewController 中,更糟糕的是:AppController(在我看来应该是一个非常简单的对象)。这通常是因为他们的示例代码试图展示一些特定的点,并且他们不想包含分解事物的复杂性(或者作者很懒惰;请选择)。因此,虽然我确实相信智能视图控制器通常运行良好,但您不应该将示例代码作为对此的演示。不幸的是,没有很多关于良好应用程序级 Cocoa 设计的规范示例,因为大多数 Cocoa 应用程序都是封闭源代码的。一个值得学习的好例子是Adium。这是一个大型、精心设计的多开发人员 Cocoa 应用程序的绝佳示例。

【讨论】:

    【解决方案2】:

    iPhone ViewController 旨在管理视图集合,所有视图组合成一个连贯的界面。例如,一个视图控制器可以管理一个带有十几个标签视图、一个开关视图和两个按钮视图的滚动视图。每个 UIView 派生的部分都处理特定元素的屏幕绘制——一个按钮、一个滚动层、一个标签——视图控制器指导哪些数据被放置在哪里。因此,UIViewController 派生类通过将数据编组到正确的 UIView 对象(如控制器)来关注 presentation(在 MVC 意义上更多的视图)。我认为 ViewController 是一个恰当的术语.

    有时为了管理单个屏幕,一个 UIViewController 将有几个其他 UIViewControllers 用于显示的特定部分。例如,UINavigationController 维护一个 UIViewController 堆栈,每个 UIViewController 处理一个显示页面。 Cocoa 的意义在于分层。

    UIViewController 可能并且经常确实有一个 delegate(有时还有一个数据源),它用于询问哪些数据属于视图并过滤用户输入.在我看来,这使得委托更接近 MVC 控制器,因为它们是管理所有模型并包含任何应用程序(业务)逻辑的类。 AppDelegate 是大的,负责管理应用程序的整体状态。 AppDelegate 可以跟踪所有数据,也可以将部分数据分发给其他代表。我希望 Facebook 应用程序有一个代表来管理所有事件,另一个代表墙上的帖子,第三个代表照片,每个代表都向 AppDelegate 报告以与 Facebook 服务器进行通信。

    当我编写应用程序时,我倾向于将 CoreData 用于 MVC 模型,将 Delegates 用于 MVC 控制器,并将 MVC 视图留给 UIViewControllers 来处理 UIViews 群。

    【讨论】:

      【解决方案3】:

      它不是一个控制器,它是一个视图控制器。这在类名中要么是显式的(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-c​​alls-a-function-that-c​​alls-a-function 找出企业软件正在使用可以用 1 行 Python 表示的密码哈希算法。 (我只是稍微夸大了一点。)

      (那么当您决定天气单元的总体布局适合显示月相/能见度时会发生什么?将通用的东西移到超类并创建一个 AstronomerCell 或其他什么。)

      另外,如果您的视图不能与模拟控制器一起工作,那么您做错了。视图不应该知道它们的视图控制器;视图控制器应该将自己注册为动作目标(我认为是 addAction:target:forControlEvents:)或适当的委托。他们都不希望目标是视图控制器。

      【讨论】:

        【解决方案4】:

        这只是一个猜测。但我的猜测是,视图和控制器最终在 Mac/iPhone 实现中耦合得更紧密的一个原因是,如果你将交互控制和演示分离得太多,你最终可能会得到一种更丑陋和更不直观的感觉接口增加。而更紧密的耦合鼓励开发人员使模型的控制更紧密地适应用户行为中的细微差异,因为他们对视图呈现的感知响应。您最终会得到更多 UI 优化但更不便携的代码。需要价值判断。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-11-04
          • 1970-01-01
          • 2021-08-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-20
          • 2021-08-10
          相关资源
          最近更新 更多