I want to hook up a UIButton to a piece of code – from what I have found, the preferred method to do this in Swift is still to use the addTarget(target: AnyObject?, ac
This is easily solved using RxSwift
import RxSwift
import RxCocoa
...
@IBOutlet weak var button:UIButton!
...
let taps = button.rx.tap.asDriver()
taps.drive(onNext: {
// handle tap
})
Edit:
I wanted to acknowledge that RxSwift/RxCocoa is a pretty heavy-weight dependency to add to a project just to solve this one requirement. There may be lighter-weight solutions available or just stick with target/action pattern.
In any case, if the idea of a general purpose declarative approach to handling application and user events appeals to you, definitely give RxSwift a look. It's the bomb.
You can approach this with a proxy class that routes events through the target / action (selector) mechanism to a closure of your making. I have done this for gesture recognizers, but the same pattern should hold for controls.
You could do something like this:
import UIKit
@objc class ClosureDispatch {
init(f:()->()) { self.action = f }
func execute() -> () { action() }
let action: () -> ()
}
var redBlueGreen:[String] = ["Red", "Blue", "Green"]
let buttons:[UIButton] = map(0..<redBlueGreen.count) { i in
let text = redBlueGreen[i]
var btn = UIButton(frame: CGRect(x: i * 50, y: 0, width: 100, height: 44))
btn.setTitle(text, forState: .Normal)
btn.setTitleColor(UIColor.redColor(), forState: .Normal)
btn.backgroundColor = UIColor.lightGrayColor()
return btn
}
let functors:[ClosureDispatch] = map(buttons) { btn in
let functor = ClosureDispatch(f:{ [unowned btn] in
println("Hello from \(btn.titleLabel!.text!)") })
btn.addTarget(functor, action: "execute", forControlEvents: .TouchUpInside)
return functor
}
The one caveat of this, is that since addTarget:... does not retain the target, you need to hold on to the dispatch objects (as done with the functors array). You don't strictly need to hold on to the buttons of course, as you could do that via a captured reference in the closure, but likely you will want explicit references.
PS. I tried to test this in playground, but could not get sendActionsForControlEvents to work. I have used this approach for gesture recognizers though.