0

我的应用程序有许多按钮,其行为取决于它们生成的事件:.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 方面还没有足够的经验来了解如何重构我的代码来做到这一点,并且还弱地捕获我的目标和对象、识别我的目标以及消除发送者之间的歧义等。

根据这个答案:将闭包作为目标添加到 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
     }
}

非常感谢您的帮助。谢谢你。

4

0 回答 0