问题描述
我正在尝试使用协议扩展在某些 UITextFieldDelegate
的方法上添加默认行为,如下所示:
I'm trying to add a default behavior on some UITextFieldDelegate
's methods using protocol extensions like so :
extension ViewController: UITextFieldDelegate {
// Works if I uncommented this so I know delegates are properly set
// func textFieldShouldReturn(textField: UITextField) -> Bool {
// textField.resignFirstResponder()
// return true
// }
}
extension UITextFieldDelegate {
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
正如您可能猜到的那样,键盘永远不会消失。我真的不知道这里的问题在哪里。这是语言限制吗?有人已经成功了吗?
As you may guess, the keyboard never dismiss. I can't really see where's the problem here. Is this a language limitation ? Did someone already success doing it ?
编辑:
正如@Logan建议的那样,默认协议的方法实现不适用于标记为 @objc
的协议。但是, UITextFieldDelegate
具有以下签名公共协议UITextFieldDelegate:NSObjectProtocol {...}
As @Logan suggested, default protocol's method implementation doesn't work with protocols marked as @objc
. However, UITextFieldDelegate
has the following signature public protocol UITextFieldDelegate : NSObjectProtocol {...}
我测试 NSObjectProtocol
的默认实现,它似乎工作正常:
I've test default implementation for NSObjectProtocol
and it seems to works fine :
protocol Toto: NSObjectProtocol {
func randomInt() -> Int
}
extension Toto {
func randomInt() -> Int {
return 0
}
}
class Tata: NSObject, Toto {}
let int = Tata().randomInt() // returns 0
推荐答案
我不能成为100%肯定,但这是我认为发生的事情:
I can't be 100% positive, but here's what I believe is happening:
无法从 ObjC
访问协议扩展。由于 UITextFieldDelegate
是 ObjC
协议,因此它依赖于 ObjC
调度。就编译器而言,默认实现中的方法是不可访问的,即使它们确实存在。
Protocol extensions aren't accessible from ObjC
. Since UITextFieldDelegate
is an ObjC
protocol, its reliant on ObjC
dispatching. As far as the compiler is concerned, the methods in your default implementation are inaccessible, even though they do exist.
为了澄清,我们可以扩展这些协议,如果它真的是扩展并添加行为。这种行为只能在Swift中访问,并且不应该以任何方式存在问题。
To clarify, we can extend these protocols if its truly an extension and adds behavior. This behavior will only be accessible in Swift and shouldn't be problematic in any way.
问题是默认实现不是 ObjC
access。
The problem is default implementations not being ObjC
accessible.
以下是自定义版本的快速示例:
Here's a quick example of a custom version:
@objc protocol Test : class {
func someFunc() -> String
}
extension Test {
func someFunc() -> String {
return ""
}
}
// Fails here 'candidate is not @objc but protocol requires it`
class Hi : NSObject, Test {
}
Xcode建议附加 @objc
但它会一遍又一遍地建议这个,直到你得到 @objc @objc @objc你好:...
Xcode suggests appending @objc
but it will keep suggesting this over and over again until you get @objc @objc @objc Hi : ...
根据我们下面的对话,我做了这个似乎有效。我无法完全解释为什么:
Based on our conversation below, I made this which seems to be working. I can't fully explain why yet:
@objc public protocol Toto: UITextFieldDelegate {
optional func randomInt() -> Int
}
extension Toto {
func randomInt() -> Int {
return 0
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
return false
}
}
class Tata: NSObject, Toto {
}
好的,我意识到我正在考虑一个不同的问题,虽然这个编译,但它不起作用,问题是动态调度。如果您尝试使用 @objc
或 dynamic
附加方法,编译器会警告您可以'除了课程外,这种方式都是这样发送的。由于协议异常不符合这一点,当ObjC调度消息send时,它无法在您的扩展中找到实现。
Ok, I realize that I'm considering a different problem, and while this compiles, it won't work, and the issue is dynamic dispatch. If you try to append your method w/ @objc
, or dynamic
, the compiler will warn you that you can't dispatch this way, except on classes. Since a protocol exception doesn't conform to this, when ObjC dispatches the message send, it can't find the implementation in your extension.
由于Swift不断更新,这个答案适用时:
Since Swift is constantly updating, here's when this answer was applicable:
Swift 2.0 Xcode 7 GM
Swift 2.0 Xcode 7 GM
这篇关于swift 2.0 - UITextFieldDelegate协议扩展无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!