我正在尝试使用协议扩展在某些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
答案 0 :(得分:9)
我无法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 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 {
}
好的,我意识到我正在考虑一个不同的问题,虽然这个编译,但它不会起作用,而且问题是动态调度。如果您尝试附加方法w / @objc
或dynamic
,编译器会警告您不能以这种方式调度,除了类。由于协议异常并不符合此要求,当ObjC发送消息发送时,它无法在您的扩展中找到实现。
由于Swift不断更新,所以这个答案适用时:
Swift 2.0 Xcode 7 GM
答案 1 :(得分:3)
这里有很好的讨论,也正是我现在怀疑的。 这里没有提到的另一件事 - 也许这可能是由于更广泛的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)) <UITextFieldDelegate>
- (void)textFieldDidBeginEditing:(UITextField * __nonnull)textField;
@end
但是,使用协议扩展如下(类似于你的帖子):
class MyViewController: UIViewController, MyTextFieldDelegateProtocol {
// ...
}
@objc protocol MyTextFieldDelegateProtocol: UITextFieldDelegate {}
extension MyTextFieldDelegateProtocol {
func textFieldDidBeginEditing(textField: UITextField) {
print("shouldChangeCharactersInRange called")
}
}
在协议的Swift标头中生成以下内容:
SWIFT_PROTOCOL("_TtP8MyApp27MyTextFieldDelegateProtocol_")
@protocol MyTextFieldDelegateProtocol <UITextFieldDelegate>
@end
实现根本不可见,因此似乎暗示obj-c不支持协议扩展实现。我也发现有人在这里问了这个问题(虽然还没有答案): Can Swift Method Defined on Extensions on Protocols Accessed in Objective-c
不幸的是,我还没有找到任何有关此限制的官方苹果文档。