Can I make #selector refer to a closure in Swift?

Blaszard picture Blaszard · May 2, 2016 · Viewed 18.8k times · Source

I want to make a selector argument of my method refer to a closure property, both of them exist in the same scope. For example,

func backgroundChange() {
    self.view.backgroundColor = UIColor.blackColor()
    self.view.alpha = 0.55

    let backToOriginalBackground = {
        self.view.backgroundColor = UIColor.whiteColor()
        self.view.alpha = 1.0
    }

    NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: #selector(backToOriginalBackground), userInfo: nil, repeats: false)
}

However, this shows an error: Argument of #selector cannot refer to a property.

Of course I can define a new, separate method and move the implementation of the closure to it, but I want to keep it frugal for such a small implementation.

Is it possible to set a closure to #selector argument?

Answer

werediver picture werediver · May 2, 2016

Not directly, but some workarounds are possible. Take a look at the following example.

/// Target-Action helper.
final class Action: NSObject {

    private let _action: () -> ()

    init(action: @escaping () -> ()) {
        _action = action
        super.init()
    }

    @objc func action() {
        _action()
    }

}

let action1 = Action { print("action1 triggered") }

let button = UIButton()
button.addTarget(action1, action: #selector(action1.action), forControlEvents: .TouchUpInside)