带有按钮和选择器的协议扩展

时间:2019-01-11 22:54:22

标签: ios swift uibutton protocols selector

我有一些协议:

@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仅可用于someButtonPressed定义的类成员,@ objc协议和类的具体扩展

有什么方法可以使用协议来实现这一目标吗?

提前感谢您的任何建议!

2 个答案:

答案 0 :(得分:0)

一种解决方法是在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()
    }

嘿,presto。

答案 1 :(得分:-1)

您需要在协议中提供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()
}