一尘不染

Swift:使用协议扩展会导致“无法识别的选择器发送到实例”

swift

我试图在所有符合协议的UIViewControllers中添加点按功能MyProtocol

以下是我的做法:

import UIKit

protocol MyProtocol: class{
    var foo: String? {get set}
    func bar()
}


extension MyProtocol where Self: UIViewController {
    func bar() {
        print(foo)
    }
}


class TestViewController: UIViewController, MyProtocol{
    var foo: String?

    override func viewDidLoad() {
        super.viewDidLoad()

        foo = "testing"
        let tapGesture = UITapGestureRecognizer(target: self, action: "bar")
}

点击屏幕时,结果如下:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: unrecognized selector sent to instance

我了解此错误,但不知道如何解决。谁能建议如何做到这一点?


阅读 186

收藏
2020-07-07

共1个答案

一尘不染

问题在于,Objective-C不了解协议扩展。因此,您不能使用协议扩展将方法注入到类中,而Objective-
C的消息传递机制可以看到该方法。您需要bar在视图控制器类 本身中 声明。

(我意识到这正是您要避免这样做的方法,但是我无能为力。)

一种解决方法可能是这样的:

override func viewDidLoad() {
    super.viewDidLoad()

    foo = "testing"
    let tapGesture = UITapGestureRecognizer(target: self, action: "baz")
    self.view.addGestureRecognizer(tapGesture)
}

func baz() {
    self.bar()
}

现在,我们使用Objective-
C的消息传递机制进行调用baz,然后使用Swift的消息传递机制进行调用bar,这当然是有效的。我意识到它并不像您想的那样干净,但是至少现在实现bar可以在协议扩展中使用。

(当然,另一种解决方案是做在协议扩展存在之前我们所做的事情:使所有视图控制器都从包含的一些通用自定义UIViewController子类继承bar。)

2020-07-07