我打开了一个(子类)NSCollectionView,其中包含多个 TextView 。每个 TextView 都映射到一个(子类)NSDocument 对象。 (想法是使用文档架构的保存功能而不是它的窗口功能,因为我需要在同一个窗口中有多个文档,而传统的文档架构不允许这样做。)
现在,我希望用户能够从主菜单调用一个功能,该功能将影响他们当前选择的文档。也就是说:该文档当前在具有当前焦点的 TextView 中可见,并且菜单命令应该对该文档进行更改。但是菜单命令的发送者只是菜单。当窗口 Controller 处理来自菜单的命令时,我如何告诉它当前选择的文档是什么?
最佳答案
这就是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 或 Storyboard中将其设置为 NSCollectionViewItem
的自定义类。
接下来,如果您的单元格 View (您的 NSCollectionViewItem
拥有的 View )不是 NSView
的自定义子类,您应该将其设为自定义子类。您必须覆盖 acceptsFirstResponder
才能返回 true:
class DocumentCellView: NSView {
override var acceptsFirstResponder: Bool { return true }
// @IBOutlets and whatnot here...
}
确保在 Storyboard或 xib 中将其设置为单元格 View 的自定义类。
最后,将菜单项的操作连接到 First Responder 上的 doThatThing:
:
这是它的工作原理:
因为单元格 View 现在为 acceptsFirstResponder
返回 true,当用户单击 Collection View 中的单元格 View 时,系统将使其成为第一响应者(开始响应者链)。
当一个 View 有一个 View Controller 时,它使该 View Controller 成为响应者链中其自身之后的下一个响应者(如果您使用的是 OS X 10.10 Yosemite 或更高版本)。您的单元格 View 有一个 View Controller :您从 outlineView:itemForRepresentedObjectAtIndexPath:
返回的项目对象。 (NSCollectionViewItem
是 NSViewController
的子类,因此您的自定义项目是一个 View Controller 。)
当用户单击菜单项时,菜单项要求 NSApplication
沿着响应者链发送它的操作,从第一个响应者开始。第一响应者是单元格 View ,但它不响应 doThatThing:
消息。所以 NSApplication
向 View 询问它的 nextResponder
,它是 NSCollectionViewItem
子类的一个实例。该对象确实响应doThatThing:
,因此NSApplication
发送doThatThing:
到你的item对象(使用 >NSMenuItem
对象作为 sender
参数)并且不检查响应链的其余部分。
关于swift - 从 NSCollectionView 获取当前焦点的文档对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38774557/