Swift协议实现另一个@objc协议

时间:2017-11-04 09:33:49

标签: ios swift4

使用Swift 4,我试图编写一个自定义协议,提供与@objc协议的一致性。

一些代码

更具体地说,我有一个自定义协议Searchable,它提供了UIKit协议UISearchBarDelegate的简单实现,只需要实现一个回调来处理搜索过滤器更改。

@objc protocol Searchable: class, UISearchBarDelegate {
  @objc func searchFilterChanged(_: String?)
}

我在协议扩展中提供了委托实现:

extension Searchable {
  func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    searchFilterChanged(searchText)
  }
  // .. and some other delegate methods
}

最后,在另一个扩展中,我创建并安装了搜索栏(必须从具体视图控制器的installSearchBar调用viewDidLoad):

extension Searchable where Self: UITableViewController {
  func installSearchBar() {
    let searchBar = UISearchBar()
    searchBar.delegate = self
    tableView?.tableHeaderView = searchBar
  }
}

问题

不幸的是,当用户在搜索栏中输入文本时,不会调用UISearchBarDelegate的委托方法。编译器用这条消息警告我:

  

非 - ' @ objc'方法' searchBar(_:textDidChange :)'不满足   ' @ objc'的可选要求protocol' UISearchBarDelegate'

但是,我无法将@objc添加到方法中,因为这会导致以下编译器错误:

  

@objc只能用于类成员,@ objc协议和   类的具体扩展

问题

所以现在我的问题是:可以在Swift中实现所需的行为,还是不可能在另一个协议中实现与@objc协议的一致性?

注1:我知道这可以使用子类来实现;我还在寻找POP版本。

注2:我知道有UISearchController也有助于简化搜索实施;我不能使用这个类,因为在我的实际代码中,我有一个更复杂的过滤器视图和其他控件 - 这就是我使用裸UISearchBar的原因。

1 个答案:

答案 0 :(得分:5)

这是因为Obj-C运行时使用动态调度(动态查找/消息传递)来符合对象,以确定它是否确认了所需的方法并调用它。

默认情况下,Swift协议扩展使用静态分派。从某种意义上说,当UISearchBarDelegate将消息传递给符合此协议的类时,它无法找到扩展方法,因为这对协议是静态的。因此,运行时既未检测到您的实现,也未运行。

这是一个非常深刻的话题。我不希望你用我简单的段落清楚。但是,当Swift协议扩展是新的(尝试概括UITableViewDelegate和DataSource)时,我尝试了这一点,但都是徒劳的。我必须研究为什么,我可以从我的经验和研究中告诉你,这与Objc消息传递有关,依赖于静态调度的动态调度和协议扩展。