Cocoa / iOS / iPhone中的模型对象所有权和MVC

Posted

技术标签:

【中文标题】Cocoa / iOS / iPhone中的模型对象所有权和MVC【英文标题】:Model object ownership and MVC in Cocoa / iOS / iPhone 【发布时间】:2011-10-01 15:42:22 【问题描述】:

我正在尝试了解如何更好地实现模型-视图-控制器设计模式。

什么对象应该“拥有”模型对象?单个控制器是否应该实例化(拥有)模型对象?

这是一个示例场景:

我有一个包含两个 UIViewController(controllerA 和 controllerB)的 UITabbarController。显然,这些控制器都不拥有彼此。我有一个模型对象,其中包含一些数据并执行一些网络活动。 controllerA 和 controllerB 都需要能够对 Model 对象进行更改。 controllerB 需要知道何时对 Model 对象进行了更改(通过 controllerA 或从网络活动返回的结果)。从最近的阅读:

我需要模型对象和控制器 B 之间的 KVO? 模型对象应该是单例吗?这样两个控制器都可以修改它? 在更简单的应用程序中,我让 viewController 拥有 Model 对象。有什么方法可以让一个控制器实例化 Model 对象,而其他控制器可以对其进行写访问? 我还阅读了有关使用应用程序委托拥有模型对象并允许控制器通过应用程序委托共享实例进行访问的信息。这似乎有点难看 - 使用应用程序委托单例全局访问我的模型对象。让我的模型对象成为单例不是更好吗? 我看到有人在 SO 上给this 链接到 iPhoneDevSDK,但他的方法的原因让我无法理解。再说一次,这不是让应用程序委托参与一些应该只是单例的事情吗?

主要是,除了通过 Model 作为单例之外,两个 Controller 是否可以通过其他方式访问(写入)一个 Model?

此外,当一个控制器拥有另一个控制器时(例如,在 UINavigationController 中,当根视图控制器实例化另一个视图控制器以堆叠在自身之上时),共享模型的最佳方法是让根视图控制器实例化模型,并在将其推送到导航堆栈之前将其传递给下一个视图控制器)?

【问题讨论】:

【参考方案1】:

随着项目的扩展,在 AppDelegate 中存储全局对象变得非常难看。

问问自己:这个模型对象与我的应用程序中的其他对象之间的关系是什么?关系是 1 对 1 还是 1 对 n。如果您只需要一个模型供各种对象访问,那么请选择单例方法。如果您需要一个对象恰好具有一个模型,则在该对象中保留一个指向它的指针。

当面对不同但计算正确的设计替代方案时,需要考虑几个方面

    哪种方法可以最大限度地减少代码行数? 哪种方法引起的耦合和语义耦合最少? 从刚接触项目的程序员的角度来看,哪种方法更容易理解、维护,也更难无意中引入错误。

如果您开始将全局模型滚动到 AppDelegate 中,您最终将创建一个难以理解且难以维护的整体类。如果在每个控制器中创建指向模型的指针,则每次实例化新控件时都必须传递对该模型的引用,并且必须将指针传递给它实例化的任何需要的对象。本质上,您创建了传递相同指针的级联瀑布,使您的接口文件和构造函数膨胀。想象一下,如果您需要跟踪 5 个模型对象而不是 1 个模型。对象每次都需要传递给构造函数的 5 个模型的 5 个指针有意义吗?这就是如何让您的项目出错且无法维护的方法。

以防不明显。 AppDelegate 只是一个单例。当您在应用委托中滚动所有模型时,您并没有避免使用单例,您只是创建了一个单体。

关于 KVO:这取决于您要完成的任务。我将举例说明 KVO 的用处。假设您有一个模型对象存储应用程序的用户偏好。

@interface SettingsModel
.....
@property (nonatomic, retain) UIColor * backgroundColor;
@end

应用程序中的其他视图应在此设置更改时立即更新其背景颜色。这可以使用 KVO 轻松解决:

[[SettingsModel getInstance] addObserver:self forKeyPath:@"backgroundColor" options:0 context:nil];


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
     if ([keyPath isEqualToString:@"backgroundColor"])
         self.view.backgroundColor = [[SettingsModel getInstance] backgroundColor];
     

【讨论】:

感谢 lorean,很好的回答!非常感谢。【参考方案2】:

模型可以被多个控制器引用。要深入了解 iPhone 开发中模型-视图-控制器的基础知识,请浏览斯坦福大学 iPhone 开发课程的前 2 节课(可在 iTunesU 免费获得,请参阅斯坦福大学http://www.stanford.edu/class/cs193p/cgi-bin/drupal/ 的信息)似乎有让控制器了解视图和/或模型更新的更多方法。

我不知道为什么你被困在单例上,我也看不出制作单例模型对象的问题。我认为您还需要考虑线程安全和内存泄漏。

【讨论】:

嗨 Rolf,我问的是单例,因为我不知道两个控制器(彼此都不拥有)写入同一个模型对象的任何其他方式。你知道一种方法吗?我看过那些讲座,谢谢。 嗨,马特,不确定,还没有完成课程 ;-) 我知道可可没有依赖注入框架,所以现在我会说单例是可以的。

以上是关于Cocoa / iOS / iPhone中的模型对象所有权和MVC的主要内容,如果未能解决你的问题,请参考以下文章

Cocoa Touch 中的 MVC:视图和模型如何交互?

Cocoa设计模式(iOS常用设计模式) Cocoa Design Patterns

Cocoa/iPhone:如何防止凳子在 xib 文件中输出不可本地化的字符串?

如何让 Cocoa 明白我的 iPhone 应用程序不是英文的?

Cocoa:在模型中使用观察者

基于 Cocoa 文档的应用程序中的 MVC