我有一个(子类)NSCollectionView打开,包含多个文本视图。每个文本视图都映射到(子类)NSDocument对象。 (我的想法是使用文档架构的保存功能,但不使用它的窗口函数,因为我需要在同一个窗口中放置多个文档,传统的文档架构不允许这样做。)
现在,有一个功能我希望用户能够从主菜单调用,这将影响他们当前选择的文档。即:文档当前在具有当前焦点的文本视图中可见,并且菜单命令应该对该文档进行更改。但是菜单命令的发送者只是菜单。当窗口控制器从菜单处理命令时,如何判断当前所选文档是什么?
答案 0 :(得分:1)
这是the responder chain的用途。
由于您使用的是NSCollectionView
,因此您可能已经拥有NSCollectionViewItem
的子类。如果没有,请创建一个。在此子类中实现您的操作方法。例如:
class DocumentItem: NSCollectionViewItem {
var document: MyDocument? {
return representedObject as? MyDocument
}
@IBAction func doThatThing(sender: AnyObject?) {
Swift.print("This is where I do that thing to \(document)")
}
// @IBOutlets and whatnot here...
}
您可能需要将其设置为xib或情节提要中NSCollectionViewItem
的自定义类。
接下来,如果您的单元格视图(您的NSCollectionViewItem
拥有的视图)不是NSView
的自定义子类,则应将其设为自定义子类。您必须覆盖acceptsFirstResponder
才能返回true:
class DocumentCellView: NSView {
override var acceptsFirstResponder: Bool { return true }
// @IBOutlets and whatnot here...
}
确保将其设置为storyboard或xib中单元格视图的自定义类。
最后,将菜单项的操作连接到First Responder上的doThatThing:
:
以下是它的工作原理:
因为单元格视图现在为acceptsFirstResponder
返回true,当用户单击集合视图中的单元格视图时,系统将使其成为第一响应者(响应者的开始)链)。
当视图具有视图控制器时,它会使视图控制器成为响应者链中的下一个响应者(如果您使用的是OS X 10.10 Yosemite或更高版本)。您的单元格视图有一个视图控制器:您从outlineView:itemForRepresentedObjectAtIndexPath:
返回的项目对象。 (NSCollectionViewItem
是NSViewController
的子类,因此您的自定义项是视图控制器。)
当用户点击菜单项时,菜单项要求NSApplication
从响应者链发送其动作,从第一个响应者开始。第一个响应者是单元格视图,但它不响应doThatThing:
消息。因此NSApplication
会向视图询问其nextResponder
,它是您的NSCollectionViewItem
子类的实例。该对象会回复doThatThing:
,因此NSApplication
会将doThatThing:
发送到您的商品对象(NSMenuItem
对象为sender
参数)并且不检查响应者链的其余部分。