swift 2.0 - UITextFieldDelegate 协议扩展不工作
swift 2.0 - UITextFieldDelegate protocol extension not working
我正在尝试使用像这样的协议扩展在某些 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 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 发送消息时,它无法在您的扩展中找到实现。
由于 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生成的header中为扩展生成如下:
@interface MyViewController (SWIFT_EXTENSION(MyApp)) <UITextFieldDelegate>
- (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 header 中为协议生成以下内容:
SWIFT_PROTOCOL("_TtP8MyApp27MyTextFieldDelegateProtocol_")
@protocol MyTextFieldDelegateProtocol <UITextFieldDelegate>
@end
实现根本不可见,因此似乎暗示 obj-c 不支持协议扩展实现。我还发现有人在这里问了这个问题(虽然还没有答案):
Can Swift Method Defined on Extensions on Protocols Accessed in Objective-c
遗憾的是,我还没有找到任何关于此限制的苹果官方文档。
我正在尝试使用像这样的协议扩展在某些 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 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 发送消息时,它无法在您的扩展中找到实现。
由于 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生成的header中为扩展生成如下:
@interface MyViewController (SWIFT_EXTENSION(MyApp)) <UITextFieldDelegate>
- (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 header 中为协议生成以下内容:
SWIFT_PROTOCOL("_TtP8MyApp27MyTextFieldDelegateProtocol_")
@protocol MyTextFieldDelegateProtocol <UITextFieldDelegate>
@end
实现根本不可见,因此似乎暗示 obj-c 不支持协议扩展实现。我还发现有人在这里问了这个问题(虽然还没有答案): Can Swift Method Defined on Extensions on Protocols Accessed in Objective-c
遗憾的是,我还没有找到任何关于此限制的苹果官方文档。