这就是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...
}
确保将其设置为故事板或 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 参数)并且不检查其余部分响应者链。