在UIControl上添加多个目标操作的更有效方法

时间:2019-02-09 20:26:12

标签: ios closures uicontrol target-action

我的应用有许多按钮,其行为取决于它们生成的事件:.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
     }
}

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

0 个答案:

没有答案