Aar*_*ron 21 protocols objective-c ios swift swift3
我有我认为是一个非常简单的协议扩展,我UIViewController
提供了通过轻击手势解雇键盘的功能.这是我的代码:
@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)
}
}
Run Code Online (Sandbox Code Playgroud)
问题是上面的代码在这一行引发编译错误:
let tap = UITapGestureRecognizer(target: self, action: #selector(Self.on(tap:)))
Run Code Online (Sandbox Code Playgroud)
带有错误消息:
'#selector'的参数是指没有暴露给Objective-C的实例方法'on(tap :)'
建议通过@objc
之前添加"修复它"func on(tap: UITapGestureRecognizer)
好的,我添加标签:
@objc func on(tap: UITapGestureRecognizer) {
dismissKeyboard()
}
Run Code Online (Sandbox Code Playgroud)
但是,它会在这个新添加的@objc
标记上抛出一个不同的编译错误,并显示错误消息:
@objc只能用于类的成员,@ objc协议和类的具体扩展
通过删除我刚刚被告知添加的完全相同的标签来建议"修复它" .
我原先认为@objc
在我的协议定义之前添加可以解决任何#selector
问题,但显然情况并非如此,这些周期性错误消息/建议没有丝毫帮助.我已经@objc
在各处添加/删除标签optional
,将方法标记为,将方法放在协议的定义中等等.
我在协议定义中放置的内容也无关紧要使扩展名保持不变,以下示例不起作用,也不对协议定义中声明的方法进行任何组合:
@objc protocol KeyboardDismissing {
func on(tap: UITapGestureRecognizer)
}
Run Code Online (Sandbox Code Playgroud)
这让我觉得它可以通过编译作为一个独立的协议来工作,但第二个我尝试将它添加到一个视图控制器:
class ViewController: UIViewController, KeyboardDismissing {}
Run Code Online (Sandbox Code Playgroud)
它吐回原来的错误.
有人可以解释我做错了什么以及如何编译它?
注意:
我已经看过这个问题,但它是针对Swift 2.2而不是Swift 3,一旦创建了一个继承自示例中定义的协议的视图控制器类,答案就会编译.
我也看了这个问题,但答案使用NotificationCenter
的不是我所追求的.
如果还有其他看似重复的问题,请告诉我.
Fré*_*dda 40
马特的回答是正确的.但是,我只想补充一点,如果您正在处理#selector以使用NotificationCenter通知,您可以尝试通过使用闭包版本来避免#selector.
例:
而不是写:
extension KeyboardHandler where Self: UIViewController {
func startObservingKeyboardChanges() {
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillShow(_:)),
// !!!!!
// compile error: cannot be included in a Swift protocol
name: .UIKeyboardWillShow,
object: nil
)
}
func keyboardWillShow(_ notification: Notification) {
// do stuff
}
}
Run Code Online (Sandbox Code Playgroud)
你可以写:
extension KeyboardHandler where Self: UIViewController {
func startObservingKeyboardChanges() {
// NotificationCenter observers
NotificationCenter.default.addObserver(forName: .UIKeyboardWillShow, object: nil, queue: nil) { [weak self] notification in
self?.keyboardWillShow(notification)
}
}
func keyboardWillShow(_ notification: Notification) {
// do stuff
}
}
Run Code Online (Sandbox Code Playgroud)
mat*_*att 14
这是一个Swift协议扩展.Swift协议扩展对于Objective-C是不可见的,无论如何; 它对它们一无所知.但是#selector
关于Objective-C看到并调用你的函数.这不会发生,因为您的on(tap:)
函数仅在协议扩展中定义.因此编译器正确地阻止了你.
这个问题是一大类问题之一,人们认为他们通过协议扩展在处理Cocoa时会变得聪明,试图通过协议将Objective-C可调用功能(选择器,委托方法等)注入类中延期.这是一个吸引人的概念,但它不会起作用.
归档时间: |
|
查看次数: |
7894 次 |
最近记录: |