swift 2.0 – UITextFieldDelegate协议扩展无法正常工作
我正在尝试使用协议扩展在某些UITextFieldDelegate
的方法上添加默认行为,如下所示:
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 } }
你可能猜到,键盘永远不会消失。 我真的不知道这里的问题在哪里。 这是语言限制吗? 有人已经成功做到了吗?
编辑:
正如@Logan所建议的那样,默认协议的方法实现不适用于标记为@objc
协议。 但是, UITextFieldDelegate
具有以下签名public protocol UITextFieldDelegate : NSObjectProtocol {...}
我测试了NSObjectProtocol
默认实现,它似乎工作正常:
protocol Toto: NSObjectProtocol { func randomInt() -> Int } extension Toto { func randomInt() -> Int { return 0 } } class Tata: NSObject, Toto {} let int = Tata().randomInt() // returns 0
我不能100%肯定,但这是我认为发生的事情:
无法从ObjC
访问协议扩展。 由于UITextFieldDelegate
是一个ObjC
协议,它依赖于ObjC
调度。 就编译器而言,默认实现中的方法即使存在也无法访问。
为了澄清,我们可以扩展这些协议,如果它真正的扩展和添加行为。 这种行为只能在Swift中访问,并且不应该以任何方式存在问题。
问题是默认实现不是ObjC
可访问的。
以下是自定义版本的快速示例:
@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 Hi : ...
建议这个,直到你得到@objc @objc @objc Hi : ...
根据我们下面的对话,我做了这个似乎有效。 我还不能完全解释为什么:
@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
附加方法,编译器将警告您不能以这种方式调度,除了类。 由于协议exception不符合这一点,当ObjC调度消息send时,它无法在您的扩展中找到实现。
由于Swift不断更新,所以这个答案适用时:
Swift 2.0 Xcode 7 GM
这里讨论得很好,而且我现在正在怀疑这一点。 这里没有提到的另一件事 – 也许这可能是由于更广泛的obj-c无法访问Swift协议扩展实现的问题。
例如,以下代码:
class MyViewController: UIViewController, MyTextFieldDelegateProtocol { @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() textField.delegate = self } } extension MyViewController: UITextFieldDelegate { func textFieldDidBeginEditing(textField: UITextField) { print("shouldChangeCharactersInRange called") } }
将在Swift生成的扩展头中生成以下内容:
@interface MyViewController (SWIFT_EXTENSION(MyApp)) - (void)textFieldDidBeginEditing:(UITextField * __nonnull)textField; @end
但是,使用协议扩展如下(类似于您的post):
class MyViewController: UIViewController, MyTextFieldDelegateProtocol { // ... } @objc protocol MyTextFieldDelegateProtocol: UITextFieldDelegate {} extension MyTextFieldDelegateProtocol { func textFieldDidBeginEditing(textField: UITextField) { print("shouldChangeCharactersInRange called") } }
在协议的Swift标头中生成以下内容:
SWIFT_PROTOCOL("_TtP8MyApp27MyTextFieldDelegateProtocol_") @protocol MyTextFieldDelegateProtocol @end
实现根本不可见,因此似乎暗示obj-c不支持协议扩展实现。 我也发现有人在这里问了这个问题(虽然还没有答案): Swift方法可以定义在Objective-c中访问的协议的扩展
不幸的是,我还没有找到任何有关此限制的官方苹果文档。