I have what I thought to be a very simple protocol extension for my UIViewController
s providing the capability to dismiss a keyboard through a tap gesture. Here's my code:
protocol Tappable {
func addTapGestureRecognizer()
func tapGestureDetected(gesture:UITapGestureRecognizer)
}
extension Tappable where Self: UIView {
func addTapGestureRecognizer() {
let gesture = UITapGestureRecognizer(target: self, action:#selector(Tappable.tapGestureDetected(_:)))
addGestureRecognizer(gesture)
}
}
class TapView: UIView, Tappable {
func tapGestureDetected(gesture:UITapGestureRecognizer) {
print("Tapped")
}
}
The problem is that the above code throws a compile error on this line:
let tap = UITapGestureRecognizer(target: self, action: #selector(Self.on(tap:)))
With the error message:
Argument of '#selector' refers to instance method 'on(tap:)' that is not exposed to Objective-C
with the suggestion to "fix it" by adding @objc
before func on(tap: UITapGestureRecognizer)
这个问题我搞了2天,才放弃了,下面是一个比较能说服我的理由:
This is a Swift protocol extension. Swift protocol extensions are invisible to Objective-C, no matter what; it knows nothing of them. But #selector is about Objective-C seeing and calling your function. That is not going to happen because your on(tap:) function is defined only in the protocol extension. Thus the compiler rightly stops you.
This question is one of a large class of questions where people think they are going to be clever with protocol extensions in dealing with Cocoa by trying to inject Objective-C-callable functionality (selector, delegate method, whatever) into a class via a protocol extension. It's an appealing notion but it's just not going to work.
翻译后是这个样子的:
这是一个快速的协议扩展。快速的协议扩展对于objective - c是看不见的,无论如何,它对它们一无所知。但是# selector是关于objective - c查看和调用你的函数。这不会发生,因为您的on(tap:)函数只在协议扩展中定义。因此编译器正确地阻止了你。
这个问题是一个很大的问题,人们认为在处理可可的过程中,他们会聪明地使用协议扩展,试图通过协议扩展将objective - c - callable功能(选择器、委托方法等)注入到类中。这是一个有吸引力的概念,但它是行不通的。
最后说一句:
在extinction协议的时候,尽量使用block,不要使用#selector了,使用回调虽然麻烦了一下,这也是一个曲线救国的方法吧。
网友评论