如何在键入时刷新 UISearchBar 搜索结果而不需要按 "Search" 按钮?有什么原生方法吗?

How to refresh UISearchBar search results when type without need to press "Search" button? Is there any native way?

我正在开发一个非常简单的应用程序,例如 Notes,并且我有 searchBar。但是,每次我想搜索时,我都必须在搜索栏中输入一些内容,然后按搜索按钮。有没有办法在我输入时进行搜索?输入一个字符 - table 刷新,输入另一个 - table 再次刷新。

这就是我的扩展程序的样子。 loadData() 是一个从 CoreData 加载数据到 tobleView 的函数。

extension ViewController: UISearchBarDelegate {

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
    let request : NSFetchRequest<Note> = Note.fetchRequest()

    request.predicate = NSPredicate(format: "text CONTAINS[c] %@", searchBar.text!)

    request.sortDescriptors = [NSSortDescriptor(key: "text", ascending: true)]

    loadData(with: request)
}

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    if searchBar.text?.count == 0 {
        getNotes()
        DispatchQueue.main.async {
            searchBar.resignFirstResponder()
        }
    } else {
        self.tableView.reloadData()
    }
}

func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    searchBar.text = ""
    searchBar.endEditing(true)

    getNotes()
}

我假设 "getNotes()" 是您查询用户保存的笔记的方法。您 should/could 所做的是向 getNotes() 添加一个完成处理程序和一个接受字符串的参数。使用委托方法 textDidChange(你已经符合)你可以做这样的事情......

    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    guard let txt = searchText.trimmingCharacters(in: .whitespacesAndNewlines), !txt.isEmpty else {return}

    getNotes(searchText: txt) { (results) in
        // Set your data source with new results
        self.src = results
        // Reload collection
        DispatchQueue.main.async {
            self.collectionView.reload()
        }
    }
}

挂钩 textDidChange 会起作用,但它有一些缺点。例如:如果用户键入速度太快,您将查询服务器(如果过滤结果是从服务器获取的)或过滤数组(如果结果是本地的)太多次,而这些过滤和查询操作并不真正重要因为用户仍在输入。

相反,您可以使用 RxSwift。这是一个了不起的图书馆,有很多用途。这个想法是将用户的输入视为事件流。然后使用 RxSwift,您可以对该事件流应用一些逻辑。例如,等待下一个 querying/filtering 操作、具有不同的值和许多其他操作的时间。

查看 this 示例。

我将代码从 searchBarSearchButtonClicked() 函数转移到 searchBar textDidChange() 函数。 现在它可以工作了,看起来像:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    if searchBar.text?.count == 0 {
        getNotes()
        DispatchQueue.main.async {
            searchBar.resignFirstResponder()
        }
    } else {
        let request : NSFetchRequest<Note> = Note.fetchRequest()
        request.predicate = NSPredicate(format: "text CONTAINS[c] %@", searchBar.text!)
        request.sortDescriptors = [NSSortDescriptor(key: "text", ascending: true)]

        getNotes(with: request)
        self.tableView.reloadData()
    }
}