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 {
}

好的,我知道我正在考虑一个不同的问题,虽然这个编译,但它不会工作,问题是动态调度。如果您尝试使用 @objcdynamic 附加您的方法,编译器将警告您不能以这种方式分派,类 除外。由于协议异常不符合这一点,当 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

遗憾的是,我还没有找到任何关于此限制的苹果官方文档。