Более эффективный способ добавить несколько Target-Actions на UIControl - PullRequest
0 голосов
/ 09 февраля 2019

Мое приложение имеет множество кнопок, поведение которых зависит от событий, которые они генерируют: .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)
     }
  }

Я стараюсь избегать постоянной необходимости писать что-то подобное, что также довольноverbose

 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
     }
}

Помощь с благодарностью.Спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...