在基于文档的 Cocoa 应用程序中避免耦合?
Posted
技术标签:
【中文标题】在基于文档的 Cocoa 应用程序中避免耦合?【英文标题】:Avoiding coupling in a document-based Cocoa app? 【发布时间】:2012-01-18 15:27:47 【问题描述】:我是 Mac 编程新手,我正在开发基于文档的应用程序。
我的NSDocument
子类创建了一个NSWindowController
子类。这个窗口控制器也创建了两个 NSViewController 子类。
有时,NSViewController
的其中一个视图的更改需要通知NSDocument
和/或主模型类。此外,需要将模型的更改通知给每个/某些视图。
我的问题是:没有(或最小)耦合的最佳方法是什么?我知道有几种选择,但我不确定哪一种最适合我的应用程序,因为我不是编程新手,而是 Cocoa 新手,尤其是 NSDocument
:
KVO。 看起来不错且易于实现,但我不喜欢不明确通知观察者有关更改的想法(AFAIK,self.someProperty = newValue
会自动执行通知观察者),并且不喜欢您必须注册可能会及时更改的属性名称的事实。
通知。我知道它们是什么,并且我已经将它们用于 ios。但我在某处读到,它们不能保证立即发送给观察者。这是真的吗?如果不是,您认为它们是基于文档的应用程序的好方法吗?
代表。是的,在正常情况下(或我通常看到的情况),一个班级有一个代表。但是创建一个代表数组也可以(刚刚测试过)。我在这里看到的问题是,每次我需要通知代表时,我都必须遍历它们,确保它们响应一个方法,然后调用该方法。
我还缺少其他选择吗?
【问题讨论】:
通知立即发送给观察者。 【参考方案1】:控制器类的 KVO 是在模型与其视图之间进行耦合的最常见方式。事实上,旨在主要消除控制器层代码的 Cocoa Bindings 是基于 KVO 的。确实,KVO/KVC 依赖于属性名称,如果这些更改,您将不得不更改连接视图的绑定或 KVO 设置。但是,让您的视图完全不了解底层模型细节通常是不可行的,因此我不认为这是一个问题。
我的建议是尽可能使用 Cocoa Binding,因为它们消除了很多胶水代码。在不能使用它们的地方,你的控制器(MVC 中的中间层)应该使用 KVO 来观察模型变化并更新适当的视图。控制器可以通过属性访问器和/或 KVC 将视图中的更改传递回模型。
【讨论】:
我不同意你不能让视图完全不知道模型。如果这是真的,NSTableView
几乎不可能为每个 Cocoa 开发人员工作。使用可用的模式(绑定、委托、数据源),您绝对可以使视图完全独立,实际上这应该是您的目标。
是的,你是对的。视图可以不知道模型,但控制器层必须知道模型和视图的细节。 OP 真的在询问控制器层(NSViewControllers 和 NSWindowControllers)。 NSTableView 本身是模型不感知的,但是用于将其连接到模型的控制器肯定需要知道模型的细节,因此在控制器类中具有硬编码的键路径也不错。
@AndrewMadsen 谢谢。刚刚切换到 KVO 并注意到更清晰的代码,除了我明确需要调用 willChangeValueForKey 和 didChangeValueForKey 的一种情况,因为如果我不调用,观察者不会注意到更改这些方法。同样,我对 KVO 还是很陌生,我知道类必须符合 KVC,但是这个是并且不会通知观察者。我猜还是需要一些知识……
您可以尝试发布一个关于未能通知观察者您正在查看的新问题。有时有充分的理由手动调用 willChange... 和 didChange... 但这种情况很少见。【参考方案2】:
是的,在正常情况下(或我通常看到的情况),一个类有 一名代表。但是创建一个代表数组也可以(只是 测试过)。
委托通常用于修改委托对象的行为。应用程序委托就是一个很好的例子: NSApplication 本身并不是很有趣;它依赖于它的委托来定义应用程序的有趣行为。如果多个委托相互冲突,那么让多个委托都试图修改单个对象的行为可能会成为问题。如果与会代表不同意怎么办?
在 Cocoa 中存在一些情况,其中一个类使用多个委托,但每个委托都有不同的角色。例如,NSTableView 有一个委托和一个数据源,但两者实际上都是某种委托。
我在这里看到的问题是每次我需要通知 代表我必须遍历它们,确保它们响应 方法,并调用该方法。
这并不难解决。例如,您可以创建一个 NSInvocation 来封装调用,然后将调用发送给每个“委托”。但是,如果您这样做,您将几乎彻底改造通知系统。如果您需要通过多代表提案获得的一对多通信,那么使用通知或 KVO 可能会更好。
【讨论】:
是的,在大多数情况下我需要一对多的通信,并且委派开始变得有点混乱。正如你们所建议的那样,我已经转移到 KVO 并且它工作得很好。谢谢!以上是关于在基于文档的 Cocoa 应用程序中避免耦合?的主要内容,如果未能解决你的问题,请参考以下文章
如何在基于 NSDocument 的 Cocoa 应用程序中使用 NSViewController
Cocoa 基于文档的应用程序:对于仅查看器的文件类型,将“保存”更改为“另存为”