我是在不同的框架上使用MVC模式一段时间,例如(swing,android,gwt ......) 现在,我正在学习iPhone框架,我对MVC实现感到非常惊讶。我问的问题是关于视图和控制器的交互。
首先,这就是我构思MVC模式的方式:
视图和控制器通过接口相互通信(一个用于视图,另一个用于控制器)
在我对MVC模式的概念中,控制器不必知道视图的属性。 (例如,控制器不能拥有视图的标签属性实例,但可以通过视图界面的方法让视图更改此标签的值)
不让控制器直接在视图UI元素上工作的优点是耦合度低,因此可以更轻松地测试视图。可以在隔离(或使用模拟控制器)上启动和测试视图。
关键是,在iPhone上,控制器(例如ViewController)直接知道UI元素,因此我不理解。 我的目标不是批评我刚刚学习的框架。但如果这真的像我描述的那样工作,我发现它真的不干净......
有没有人对这个框架进行更多实验,谁可以给我详细说明?或者,如果您对我的MVC方法有不同意见,请告诉我;)
更重要的是,我问我的方法是不是MVP(在此描述:http://code.google.com/intl/fr/webtoolkit/articles/testing_methodologies_using_gwt.html)与MVC不同。
答案 0 :(得分:12)
MVC意味着不同的东西,因为它是first formalized in Smalltalk,并且MVC的NeXTSTEP(Cocoa)版本与Smalltalk不完全匹配。 Smalltalk的分解基本上是这样的:
NeXTSTEP的分解在实践中更像是这样:
我在绘图和呈现之间进行区分,因为NSView对于数据的“含义”往往是愚蠢的。它只关注绘制像素。所以你倾向于传递它的实际字符串而不是视图撕裂并“呈现”的对象。
这不是一个巨大的差异,但它是你遇到的事情的原因。 IMO的主要转变是,通过Cocoa / NeXTSTEP,视图类变得越来越可重用。在变得如此可重复使用时,更多应用敏感部分需要移出控制器。我相信这通常是一个好处,因为它导致更少的子类,更易理解的代码和更多可重用的代码......大多数时候。特别是,它允许您更轻松地交换进行更高级绘图的视图(以特定方式设置动画或在行等上交替颜色的视图),而不会碰到通常存在于控制器中的任何特定于应用程序的逻辑。
也就是说,当一个视图特别复杂时,我发现创建更专业的视图是有益的,这些视图可以采用数据对象并管理自己的演示文稿,更像是我认为你想象的方式。
编辑:还有一点要注意。 Apple的示例代码在设计方面通常很糟糕。它们几乎从不包含模型类,并且几乎可以将所有可以想象的东西塞进ViewControllers中,更糟糕的是:AppController(在我看来应该是一个非常简单的对象)。这通常是因为他们的示例代码试图展示某些特定点,并且他们不希望包含破坏事物的复杂性(或者作者是懒惰的;请选择)。因此,虽然我确实认为智能视图控制器通常运行良好,但您不应将示例代码作为示例。不幸的是,由于大多数Cocoa应用程序都是封闭源代码,因此没有很多典型的应用程序级别Cocoa设计实例。值得学习的一个好例子是Adium。这是一个大型,精心设计的多开发人员Cocoa应用程序的绝佳示例。
答案 1 :(得分:3)
iPhone ViewController旨在管理一组视图,所有这些视图都组合成一个连贯的界面。例如,视图控制器可以管理具有十二个标签视图,切换视图和两个按钮视图的滚动视图。每个UIView派生的部分处理特定元素的屏幕绘制 - 按钮,滚动图层,标签 - 视图控制器指示将数据放在何处。因此,UIViewController派生类侧重于表示(MVC意义上的更多View),通过将数据编组到正确的UIView对象(如Controller)中。我认为ViewController是一个适合它的术语
有时为了管理单个屏幕,UIViewController将为显示的特定部分提供其他几个UIViewControllers。例如,UINavigationController维护着一堆UIViewControllers,每个UIViewControllers处理一个显示页面。可可是关于分层的。
UIViewController可能并且经常会有一个委托(有时候还有一个数据源),用于询问视图中的数据属性并过滤用户输入。在我看来,这使代表更接近MVC控制器,因为它们是管理所有模型并包含任何应用程序(业务)逻辑的类。 AppDelegate是最重要的一个,负责管理应用程序的整体状态。 AppDelegate可以跟踪所有数据,也可以将部分数据发送给其他代表。我希望Facebook应用程序有一个代表用于管理所有事件,另一个用于Wall帖子,第三个用于Photos,每个代表都报告AppDelegate与Facebook服务器进行通信。
当我编写应用程序时,我倾向于将CoreData用于MVC模型,代理MVC控制器,并将MVC视图留给UIViewControllers,负责处理UIViews群。
答案 2 :(得分:2)
它不是控制器,它是一个视图控制器。这可以是类名(UIViewController,UITableViewController)中的显式或隐式(UITabBarController,因为UITabBar是视图; UINavigationController,因为导航是范例; UINavigationController有非常薄的视图)。
我能想到的唯一非视图“控制器”是NSFetchedResultsContoller。
但为什么奇怪的设计?
部分内容与iPhone UI范例有关:用户一次与屏幕进行交互。如果看不到“屏幕”,则可以回收其大部分内存。 UIViewControllers代表一个屏幕,并管理屏幕如何与其他屏幕进行交互。
(当然,Apple在iPad上稍微扩展了这一点以实现弹出窗口/拆分视图,但这两个仍然是有效的“屏幕”而不是通用视图。视图控制器模糊地类似于桌面操作系统上的窗口,除了大多数它们在大多数时间都不可见。)
部分内容与CoreAnimation有关:UIView处理绘图/布局,并由CALayers支持。 CALayers有效地代表GPU上的纹理多边形; “层内容”(即纹理)不能任意卸载到空闲存储器。 (我不完全确定原因,但这意味着您可以将内容设置为CGImage一次并不管它。)因为很多视图的属性都由图层属性支持(frame,bounds,center,contentStretch,.. 。),让一个没有图层的视图存在有点傻。最终结果是视图是重量级的,并且当内存稀缺时它们偶尔需要消失,因此视图控制器需要跟踪视图卸载/重新加载(滚动位置,当前所选项目,......)中应该保留的内容。是的,它可以要求视图自行序列化,但序列化是 icky ,并且大多数事情不需要序列化。
部分原因与懒惰有关:您需要实现视图控制器来处理它与其他视图控制器的交互方式。另一方面,视图会自动调整 - 如果您乐意在nib或-viewDidLoad中设置布局,则通常不需要编写自定义视图。懒惰决定你没有,所以布局经常发生在视图控制器中。
就个人而言,当它看起来更有意义时,我会实施一个“智能”视图。以天气应用程序为例:当视图加载时,您必须在每个单元格中显示一堆天气(可能是也可能不是表格视图单元格;无关紧要)。获得更新后,您必须更新所有单元格。您可以实现 - [WeatherViewController updateCell:],但似乎更有意义的是 - [WeatherCell setWeather:]并将其传递给您的模型。视图控制器中的杂乱程度要低得多。
我还指责懒惰和可维护性:有时将所有内容放在一个文件中会更容易,有时候使用半重复代码和次要专业化比编写支持其所有用例的通用视图更容易。它比Enterprise Java好很多,它通常有一个函数 - 调用一个函数 - 调用一个函数 - 调用 - 一个函数 - 一个单例函数 - 实例化-with-a-factory-some-class-that-you-to-track-down)-that-calls-a-function-that-call-a-function,用于发现企业软件正在使用密码散列算法,可以用1行Python表示。 (我只是略微夸大。)
(那么当您确定天气单元的总体布局适合显示月相/可见度时会发生什么?将通用内容移动到超类并制作AstronomerCell,或其他任何内容。)
此外,如果您的视图无法使用模拟控制器,那么您做错了。视图不应该知道他们的视图控制器;视图控制器应将自己注册为动作目标(addAction:target:forControlEvents:,我认为)或适当的委托。两者都不希望目标成为视图控制器。
答案 3 :(得分:1)
这只是猜测。但我的猜测是,视觉和控制器在Mac / iPhone实现中更紧密耦合的一个原因是,如果你将交互控制和演示文稿分离得太多,你最终可能会变得更加丑陋和不那么直观的感觉界面增加。而更紧密的耦合鼓励开发人员根据对视图呈现的感知响应,使模型的控制更贴近用户行为的微妙差异。您最终会获得更多UI优化但不太可移植的代码。需要进行价值判断。