关于ios:swift 2.0-UITextFieldDelegate协议扩展不起作用

swift 2.0 - UITextFieldDelegate protocol extension not working

我正在尝试使用协议扩展在某些UITextFieldDelegate方法上添加默认行为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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的默认实现,它似乎运行良好:

1
2
3
4
5
6
7
8
9
10
11
12
13
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访问协议扩展。由于UITextFieldDelegateObjC协议,因此它依赖于ObjC调度。就编译器而言,默认实现中的方法即使存在也无法访问。

为了明确起见,我们可以扩展这些协议(如果它确实是扩展名)并增加行为。此行为只能在Swift中访问,并且绝不会出现任何问题。

问题是默认实现无法访问ObjC

这是自定义版本的快速示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@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 : ...

根据下面的对话,我认为这似乎可行。我还不能完全解释原因:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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 / @objcdynamic追加方法,则编译器将警告您,除了在类上,您不能以这种方式分派。由于协议异常不符合此要求,因此ObjC调度消息发送时,无法在扩展中找到实现。

由于Swift会不断更新,因此适用此答案的时间是:

Swift 2.0 Xcode 7 GM


这里很好的讨论,以及我在这一点上的怀疑。
此处未提及的另一件事-可能是由于obj-c无法访问Swift协议扩展实现的更广泛的问题。

例如,以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
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生成的扩展头中生成以下内容:

1
2
3
@interface MyViewController (SWIFT_EXTENSION(MyApp)) <UITextFieldDelegate>
- (void)textFieldDidBeginEditing:(UITextField * __nonnull)textField;
@end

但是,使用以下协议扩展(类似于您的帖子):

1
2
3
4
5
6
7
8
9
10
class MyViewController: UIViewController, MyTextFieldDelegateProtocol {
    // ...
}

@objc protocol MyTextFieldDelegateProtocol: UITextFieldDelegate {}
extension MyTextFieldDelegateProtocol {
    func textFieldDidBeginEditing(textField: UITextField) {
        print("shouldChangeCharactersInRange called")
    }
}

在Swift头中为协议生成以下内容:

1
2
3
SWIFT_PROTOCOL("_TtP8MyApp27MyTextFieldDelegateProtocol_")
@protocol MyTextFieldDelegateProtocol <UITextFieldDelegate>
@end

该实现完全不可见,因此似乎暗示obj-c不支持协议扩展实现。我还发现有人在这里问了这个问题(尽管还没有答案):
是否可以在Objective-c中访问的协议扩展上定义Swift方法

不幸的是,我尚未找到有关此限制的任何官方Apple文档。