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

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


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)


I tried this for UIBarButtonItem at least:

private var actionKey: Void?extension UIBarButtonItem {    private var _action: () -> () {        get {            return objc_getAssociatedObject(self, &actionKey) as! () -> ()        }        set {            objc_setAssociatedObject(self, &actionKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)        }    }    convenience init(title: String?, style: UIBarButtonItemStyle, action: @escaping () -> ()) {        self.init(title: title, style: style, target: nil, action: #selector(pressed))        self.target = self        self._action = action    }    @objc private func pressed(sender: UIBarButtonItem) {        _action()    }}

Then you can do this:

navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Test", style: .plain, action: {    print("Hello World!")})


As @gnasher729 notes, this is not possible because selectors are just names of methods, not methods themselves. In the general case, I'd use dispatch_after here, but in this particular case, the better tool IMO is UIView.animateWithDuration, because it's exactly what that function is for, and it's very easy to tweak the transition:

UIView.animateWithDuration(0, delay: 0.5, options: [], animations: {    self.view.backgroundColor = UIColor.whiteColor()    self.view.alpha = 1.0}, completion: nil)