swift 2.0 - UITextFieldDelegate协议扩展无法正常工作

Yam*_*man 20 protocols ios uitextfielddelegate swift

我正在尝试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
    }
}
Run Code Online (Sandbox Code Playgroud)

你可能猜到,键盘永远不会消失.我真的不知道这里的问题在哪里.这是语言限制吗?有人已经成功做到了吗?

编辑:

正如@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
Run Code Online (Sandbox Code Playgroud)

Log*_*gan 9

我不能100%肯定,但这是我认为正在发生的事情:

无法访问协议扩展ObjC.既然UITextFieldDelegateObjC协议,它依赖于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 {

}
Run Code Online (Sandbox Code Playgroud)

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 {
}
Run Code Online (Sandbox Code Playgroud)

好吧,我意识到我正在考虑一个不同的问题,虽然这个编译,它将无法工作,问题是动态调度.如果你尝试附加你的方法@objc,或者dynamic,编译器会警告你不能以这种方式调度,除了类.由于协议异常不符合这一点,当ObjC调度消息send时,它无法在您的扩展中找到实现.

由于Swift不断更新,所以这个答案适用时:

Swift 2.0 Xcode 7 GM

  • 好吧,如果我理解的话:协议扩展是纯粹的静态调度,所以当`UITextFieldDelegate`尝试通过`objc_msgSend()`调用他的一个方法时,它永远不会到达协议扩展的默认实现吗? (3认同)
  • 是的,我认为这是有道理的.感谢您走到最底层,我现在接受您的回答,但仍会尝试联系Apple以获得官方回复.我会告诉我是否有任何消息.干杯. (2认同)