Search code examples
swiftuicontrolresponder-chain

addTarget:action:forControlEvents: selector syntax when target is nil?


I would like a parent ViewController to handle Target-Actions generated by one of its child ViewControllers.

According to the Apple docs this should be possible by setting target to nil and following the responder chain.

If you specify nil for the target object, the control searches the responder chain for an object that defines the specified action method. https://developer.apple.com/documentation/uikit/uicontrol

But how do I write the action method signature when target is nil?

Typically you enclose the function name in #selector() which gives you compile time checks that a method exists with that signature. Like so:

class MyViewController: UIViewController {
    override func viewDidLoad() {
         self.button.addTarget(self, action: #selector(buttonPressed(sender:)), for: .touchDown)
    }

    func buttonPressed(sender: UIButton) { }

}

But since target is nil the compiler complains because it can't find it:

// ! Use of unresolved identifier "buttonPressed(sender:)"
button.addTarget(nil, action: #selector(buttonPressed(sender:)), for: .touchDown)

I tried initializing a Selector using a String, but the compiler also complains.

    // ! String literal is not a valid Objective-C selector
    button.addTarget(nil, action: Selector("buttonPressed(sender:)"), for: .touchDown)

Solution

  • The solution is to prefix with the name of the defining class.

        button.addTarget(nil, action: #selector(MyViewController.buttonPressed(sender:)), for: .touchDown)
    

    FYI I got the answer through this nice blog post from Jan 2016, downloading the source files, and having XCode convert it to Swift 3 syntax :-)