我的应用有许多按钮,其行为取决于它们生成的事件:.touchDown
,.touchUpInside
,.touchUpOutside
等
我使用典型的Target-Action机制设置以下行为:
class MyViewController: UIViewController {
let redButton = UIButton()
let blueButton = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
self.redButton.addTarget(self, action: #selector(redButtonTouchDown(_:)), for: .touchDown)
self.redButton.addTarget(self, action: #selector(redButtonTouchUpInside(_:)), for: .touchUpInside)
self.redButton.addTarget(self, action: #selector(redButtonTouchUpOutside(_:)), for: .touchUpOutside)
self.blueButton.addTarget(self, action: #selector(blueButtonTouchDown(_:)), for: .touchDown)
self.blueButton.addTarget(self, action: #selector(blueButtonTouchUpInside(_:)), for: .touchUpInside)
self.blueButton.addTarget(self, action: #selector(blueButtonTouchUpOutside(_:)), for: .touchUpOutside)
}
@objc func redButtonTouchDown(_ sender: UIButton) {
print("redButton touchDown")
}
@objc func redButtonTouchUpInside(_ sender: UIButton) {
print("redButton touchUpInside")
}
@objc func redButtonTouchUpOutside(_ sender: UIButton) {
print("redButton touchUpOutside")
}
@objc func blueButtonTouchDown(_ sender: UIButton) {
print("blueButton touchDown")
}
@objc func blueButtonTouchUpInside(_ sender: UIButton) {
print("blueButton touchUpInside")
}
@objc func blueButtonTouchUpOutside(_ sender: UIButton) {
print("blueButton touchUpOutside")
}
}
这很冗长。我的问题是:是否有一种更有效的方法来执行此操作,而无需为每种事件类型使用单独的函数?代码如下所示:
class MyViewController: UIViewController {
let redButton = UIButton()
let blueButton = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
self.redButton.addActions(for: [.touchDown, .touchUpInside, .touchUpOutside], #selector(redButtonEvents(_:_:)))
self.blueButton.addActions(for: [.touchDown, .touchUpInside, .touchUpOutside], #selector(blueButtonEvents(_:_:)))
}
func redButtonEvents(_ sender: UIButton, _ event: UIControl.Event) {
switch event {
case .touchDown:
print("redButton touchDown")
case .touchUpInside:
print("redButton touchUpInside")
case .touchUpOutside:
print("redButton touchUpOutside")
default:
break
}
}
func blueButtonEvents(_ sender: UIButton, _ event: UIControl.Event) {
switch event {
case .touchDown:
print("blueButton touchDown")
case .touchUpInside:
print("blueButton touchUpInside")
case .touchUpOutside:
print("blueButton touchUpOutside")
default:
break
}
}
}
我一直在研究各种不使用Selector
而是将方法包装在闭包中的解决方案。恐怕我对obj-c或Swift还没有足够的经验,无法了解如何重构我的代码来做到这一点,还弱捕获了我的目标和对象,确定了我的目标,并在发件人之间消除了歧义,等等。>
根据此答案:Adding a closure as target to a UIButton
class ClosureSleeve {
let closure: ()->()
init (_ closure: @escaping ()->()) {
self.closure = closure
}
@objc func invoke () {
closure()
}
}
extension UIControl {
func addAction(for controlEvents: UIControl.Event, _ closure: @escaping ()->()) {
let sleeve = ClosureSleeve(closure)
addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
objc_setAssociatedObject(self, String(format: "[%d]", arc4random()), sleeve, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
我试图避免经常写这样的东西,这也很冗长
class MyViewController: UIViewController {
let redButton = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
// this is also quite verbose
for event in [UIControl.Event]([.touchDown, .touchUpInside, .touchUpOutside]) {
self.button.addAction(for: event) { [weak self] in
if let strongSelf = self {
strongSelf.redButtonActions(strongSelf.button, event)
}
}
}
}
func redButtonActions(_ sender: UIButton, _ event: UIControl.Event) {
// handle red button actions
}
}
非常感谢您的帮助。谢谢。