从NSCollectionView获取具有当前焦点的文档对象

时间:2016-08-04 18:13:07

标签: swift macos cocoa nstextview nscollectionview

我有一个(子类)NSCollectionView打开,包含多个文本视图。每个文本视图都映射到(子类)NSDocument对象。 (我的想法是使用文档架构的保存功能,但不使用它的窗口函数,因为我需要在同一个窗口中放置多个文档,传统的文档架构不允许这样做。)

现在,有一个功能我希望用户能够从主菜单调用,这将影响他们当前选择的文档。即:文档当前在具有当前焦点的文本视图中可见,并且菜单命令应该对该文档进行更改。但是菜单命令的发送者只是菜单。当窗口控制器从菜单处理命令时,如何判断当前所选文档是什么?

1 个答案:

答案 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:

connection menu item to first responder

以下是它的工作原理:

因为单元格视图现在为acceptsFirstResponder返回true,当用户单击集合视图中的单元格视图时,系统将使其成为第一响应者(响应者的开始)链)。

当视图具有视图控制器时,它会使视图控制器成为响应者链中的下一个响应者(如果您使用的是OS X 10.10 Yosemite或更高版本)。您的单元格视图有一个视图控制器:您从outlineView:itemForRepresentedObjectAtIndexPath:返回的项目对象。 (NSCollectionViewItemNSViewController的子类,因此您的自定义项是视图控制器。)

当用户点击菜单项时,菜单项要求NSApplication从响应者链发送其动作,从第一个响应者开始。第一个响应者是单元格视图,但它不响应doThatThing:消息。因此NSApplication会向视图询问其nextResponder,它是您的NSCollectionViewItem子类的实例。该对象回复doThatThing:,因此NSApplication会将doThatThing:发送到您的商品对象(NSMenuItem对象为sender参数)并且不检查响应者链的其余部分。