我有一些协议:
@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协议和类的具体扩展。
有什么方法可以使用协议来实现这一目标吗?
提前感谢您的任何建议!
答案 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()
}