一尘不染

使用选择器错误的Swift 3协议扩展

swift

对于我的UIViewControllers ,我有一个非常简单的协议扩展,它具有通过轻击手势关闭键盘的功能。这是我的代码:

@objc protocol KeyboardDismissing { 
    func on(tap: UITapGestureRecognizer)
}

extension KeyboardDismissing where Self: UIViewController {

    func addDismissalGesture() {
        let tap = UITapGestureRecognizer(target: self, action: #selector(Self.on(tap:)))
        view.addGestureRecognizer(tap)
    }

    func on(tap: UITapGestureRecognizer) {
        dismissKeyboard()
    }

    func dismissKeyboard() {
        view.endEditing(true)
    }
}

问题是上面的代码在此行上引发了编译错误:

let tap = UITapGestureRecognizer(target: self, action: #selector(Self.on(tap:)))

带有错误信息:

“ #selector”的参数引用实例方法“ on(tap :)”,而该方法未公开给Objective-C

并建议在“ @objc之前”添加“修复”func on(tap: UITapGestureRecognizer)

好的,我添加标签:

@objc func on(tap: UITapGestureRecognizer) {
    dismissKeyboard()
}

但是,随后,它在此新添加的@objc标记上引发了不同的编译错误,并显示错误消息:

@objc只能与类的成员,@ objc协议和类的具体扩展一起使用

并建议通过 删除我刚刚被告知要添加的完全相同的标签 来“修复”它。

我本来以为@objc在协议定义之前添加即可解决任何#selector问题,但显然并非如此,这些周期性的错误消息/建议丝毫没有帮助。我对@objc在任何地方添加/删除标签optional,将方法标记为,在协议的定义中放置方法等一无所知。

我在协议定义中输入的内容也没关系,保持扩展名不变,以下示例不起作用,协议定义中声明的方法的任何组合也不起作用:

@objc protocol KeyboardDismissing { 
    func on(tap: UITapGestureRecognizer)
}

这使我误以为它可以通过作为独立协议进行编译来工作,但是第二个尝试将其添加到视图控制器中:

class ViewController: UIViewController, KeyboardDismissing {}

它会吐出原始错误。

有人可以解释我做错了什么以及如何编译吗?


阅读 206

收藏
2020-07-07

共1个答案

一尘不染

这是一个Swift协议扩展。无论如何,Objective-C都看不到Swift协议扩展。对他们一无所知。但是#selector关于Objective-
C看到并调用您的函数。那不会发生,因为您的on(tap:)功能 在协议扩展中定义。因此,编译器正确地阻止了您。

这个问题是一大类问题,人们认为通过尝试通过协议将Objective-C调用的功能(选择器,委托方法等)注入到类中,人们认为他们在处理可可时将对协议扩展很聪明。延期。这是一个吸引人的概念,但它根本行不通。

2020-07-07