How to make convenient touch handler for UIButton in iOS

Issue #308

If you don’t want to use https://github.com/onmyway133/EasyClosure yet, it’s easy to roll out a closure based UIButton. The cool thing about closure is it captures variables

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
final class ClosureButton: UIButton {
var didTouch: (() -> Void)?

override init(frame: CGRect) {
super.init(frame: frame)

addTarget(self, action: #selector(buttonTouched(_:)), for: .touchUpInside)
}

required init?(coder aDecoder: NSCoder) {
fatalError()
}

@objc private func buttonTouched(_: UIButton) {
didTouch?()
}
}

Then in cellForItem

1
2
3
4
5
6
7
8
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: UserCell = collectionView.dequeue(for: indexPath)!
let user = users[indexPath.item]
cell.powerButton.didTouch = { [weak self] in
self?.openPowerView(user)
}
return cell
}

With this we can even forward touch event to another button

1
2
3
4
5
func forwardTouchEvent(button: ClosureButton) {
didTouch = { [weak button] in
button?.didTouch?()
}
}

Another benefit is that we can apply debouncing to avoid successive tap on button

1
2
3
4
5
6
let debouncer = Debouncer(timeInterval: 0.2)
@objc private func buttonTouched(_: UIButton) {
debouncer.run { [weak self] in
self?.didTouch?()
}
}

Comments