Расширение протокола с кнопкой и селектором - PullRequest
0 голосов
/ 12 января 2019

У меня есть протокол:

@objc protocol SomeProtocol { } 

, которое я расширяю для UIViewController экземпляров. В этом расширении я хочу создать и добавить кнопку, селектор которой также определен в протоколе:

extension SomeProtocol where Self: UIViewController {

    func addSomeButton() {
        let someButton = UIButton()
        someButton.addTarget(self, #selector(someButtonPressed), for: .touchUpInside)
        view.addSubview(someButton)
    }

    @objc func someButtonPressed() {
    }

}

Однако я получаю сообщение об ошибке @ objc можно использовать только с членами классов, протоколами @objc и конкретными расширениями классов при определении someButtonPressed.

Есть ли способ добиться этого с помощью протоколов?

Заранее спасибо за любые предложения!

Ответы [ 2 ]

0 голосов
/ 12 января 2019

Обходной путь - добавить закрывающую втулку к UIButton вместо целевого действия, как показано здесь https://stackoverflow.com/a/41438789/5058116 и скопировано ниже для удобства.

typealias Closure = () -> ()

///
class ClosureSleeve {
    let closure: Closure
    init(_ closure: @escaping Closure) {
        self.closure = closure
    }
    @objc func invoke () {
        closure()
    }
}

extension UIControl {
    func addAction(for controlEvents: UIControl.Event = .touchUpInside, _ closure: @escaping Closure) {
        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)
    }
}

Затем просто замените:

someButton.addTarget(self, #selector(someButtonPressed), for: .touchUpInside)

с:

someButton.addAction { [weak self] in
        self?.someButtonPressed()
    }

и привет престо.

0 голосов
/ 12 января 2019

В протоколе необходимо указать требование Selector. Это потому, что вы можете применить атрибут @objc только к NSObject. Единственная причина пометить протокол @objc - дополнительные методы.

@objc protocol SomeProtocol {
    var action: Selector { get }
} 

Измените расширение на это:

extension SomeProtocol where Self: UIViewController {
    func addSomeButton() {
        let someButton = UIButton()
        someButton.addTarget(self, action: action, for: .touchUpInside)
        view.addSubview(someButton)
    }
}

Теперь это работает:

extension UIViewController: SomeProtocol {
    @objc func buttonPressed(sender: UIButton) {
        print("Button pressed")
    }
    var action: Selector {
        return #selector(buttonPressed(sender:))
    }
}

Использование:

let vc: myViewController: MyViewController!
func doSomething() {
  vc.addSomeButton()
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...