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)