This is what the responder chain is for.
Since you're using NSCollectionView
, you probably already have a subclass of NSCollectionViewItem
. If not, create one. Implement your action method in this subclass. Example:
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...
}
You may need to set this as the custom class of your NSCollectionViewItem
in your xib or storyboard.
Next, if your cell view (the view owned by your NSCollectionViewItem
) isn't a custom subclass of NSView
already, you should make it a custom subclass. You must override acceptsFirstResponder
to return true:
class DocumentCellView: NSView {
override var acceptsFirstResponder: Bool { return true }
// @IBOutlets and whatnot here...
}
Make sure you set this as the custom class of your cell view in your storyboard or xib.
Finally, connect the action of your menu item to doThatThing:
on First Responder:

Here's how it works:
Because the cell view now returns true for acceptsFirstResponder
, when the user clicks a cell view in the collection view, the system will make it the first responder (the start of the responder chain).
When a view has a view controller, it makes that view controller the next responder after itself in the responder chain (if you are on OS X 10.10 Yosemite or later). Your cell view has a view controller: the item object you return from outlineView:itemForRepresentedObjectAtIndexPath:
. (NSCollectionViewItem
is a subclass of NSViewController
, so your custom item is a view controller.)
When the user clicks the menu item, the menu item asks NSApplication
to send its action along the responder chain, starting with the first responder. The first responder is the cell view, but it doesn't respond to the doThatThing:
message. So NSApplication
asks the view for its nextResponder
, which is an instance of your NSCollectionViewItem
subclass. That object does respond to doThatThing:
, so NSApplication
sends doThatThing:
to your item object (with the NSMenuItem
object as the sender
argument) and doesn't check the rest of the responder chain.