How to create custom UIMenuItem for UITableViewController in Swift

I have been searching for a reply to this problem for two days now.


I have tried every single Google search result on the subject but I still can't get it working.


Essentially, I want a single custom menu item to popup when I long press on a cell, but I want to handle the selector in the UITableViewController.


I can get the selector to respond if I put everything in the cell but that wouldn't give me access to the list behind the table view.


Over 50 people have viewed my previous post but not one reply. Surely this can't be that difficult?

Replies

I'm not aware of a really good way to do this, but the brute force approach works pretty well.


In effect, you create a custom cell subclass, put the action method for the long press in the subclass, then inject a reference to the view controller into every cell you return when the table view asks you for one. The action method in the cell subclass just calls through to the view controller.


In practice, what you'd actually do is treat the view controller as a cell delegate. You would create a protocol with the method that the cell's action message invokes, and conform the view controller to the protocol.


You also need to make the cell "know" which item in the data source it represents, and add that to the passed-through call, if the view controller needs to know which cell had the long press.


Why is this so hard? Because the target-action mechanism was originally designed for the responder chain. Events can cause a search up the responder chain, looking for a target that will accept a certain action, but this breaks down when the item "detecting" the event is not ever made the first responder.


That's true of this case. The cell is a view that typically isn't first responder, but it's where the long press action is initially presented. That means you have to route your long press manually.


(One gotcha to be careful of is to avoid having your cell spontaneously call into its delegate, in situations other than when the call is triggered by a user action. That's because the cell doesn't know when it's no longer *in* the table view, and is instead just sitting in a queue of available cells.)

This is not aimed at you Quincey - this stinks of a massive bug that should have been resolved with the introduction of the newer #selector syntax that allows the specification of a fully qualified path to the handling selector. In fact, the full qualification gets totally ignored and the nearest method with the same signature gets celled instead (in this case, the one in the cell).


I have succeeded by putting a closure variable on the cell class and assigning that to the controller, and that executes correctly.


I have also seen a couple of articles on calling along the responder chain from the cell to get the table view controller to respond and I am also going to try this out.


I suppose we might not expect this kind of failing to be addressed soon; since SwiftUI seems to be the "new shiny", I'm guessing those of us supporting legacy apps (that can't easily be moved to SwiftUI) by adding new features to them could be left high and dry.

OK, I gave up with the responder chain. All sorts of weirdities there. In the end, I attached a closure to the cell, handled in the table view controller. So much for sophistication 😎