【问题标题】:Live search throttle in Swift 3Swift 3 中的实时搜索限制
【发布时间】:2017-07-15 14:53:09
【问题描述】:

我正在尝试使用 Swift 在我的 PHP API 上进行实时搜索。到目前为止,我已经完成了这件事。

 var filteredData = [Products]()


 func getSearch(completed: @escaping DownloadComplete, searchString: String) {

        let parameters: Parameters = [
            "action" : "search",
            "subaction" : "get",
            "product_name"  : searchString,
            "limit" : "0,30"
        ]
        Alamofire.request(baseurl, method: .get, parameters: parameters).responseJSON { (responseData) -> Void in
            if((responseData.result.value) != nil) {
                let result = responseData.result

                if let dict = result.value as? Dictionary<String, AnyObject>{
                    if let list = dict["products_in_category"] as? [Dictionary<String, AnyObject>] {
                        if self.filteredData.isEmpty == false {
                            self.filteredData.removeAll()
                        }
                        for obj in list {
                            let manPerfumes = Products(productDict: obj)
                            self.filteredData.append(manPerfumes)
                        }
                    }
                }
                completed()
            }
        }
    }


extension SearchViewController: UISearchResultsUpdating {

    func updateSearchResults(for searchController: UISearchController) {

        if (searchController.searchBar.text?.characters.count)! >= 3 {
                    self.getSearch(completed: {
                    self.searchResultTable.reloadData()

                    self.searchResultTable.setContentOffset(CGPoint.zero, animated: true)
                }, searchString: searchController.searchBar.text!)


        } else {
            self.searchResultTable.reloadData()
        }


    }
}

表格视图正在更新为filteredData。 我怎样才能限制搜索,所以让我们说用户何时写

"example" -> shows the results with example
then he erase the "le" -> 
"examp" -> if the previous request is not completed, cancel it -> make request for "examp" and show the data in table view!

附:从我找到的另一个答案

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    // to limit network activity, reload half a second after last key press.
    NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(self.reload), object: nil)
    self.perform(#selector(self.reload), with: nil, afterDelay: 0.5)
}
func reload() {
    print("Doing things")
}

虽然如果我尝试用我的函数替换“self.reload”,我得到一个错误 cannot convert value of type () to expected argument type selector

【问题讨论】:

  • 如何将self.reload 函数替换为cancelPreviousPerformRequests 选择器参数?你好像忘了把那个函数放在#selector
  • 因为如果我尝试这样做,我会得到与您相同的错误:NSObject.cancelPreviousPerformRequests(withTarget: self, selector: self.fetchFriends(user:completion:), object: nil)。注意到我没有将#selector 添加到我的函数中吗?
  • @rockyraccoon 还是同样的错误!
  • 好吧,我试着复制你想要完成的事情,我没有收到任何错误:func searchBar() { NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(self.getSearch(completed:searchString:)), object: nil) perform(#selector(self.getSearch(completed:searchString:)), with: nil, afterDelay: 0.5) }
  • @rockyraccoon 好的,这没有错误!你在哪里对。虽然在执行,但如何将字符串传递给函数?

标签: ios swift swift3 uisearchbar alamofire


【解决方案1】:
  • 免责声明:我是一名作家。

Throttler 可能是完成它的正确工具。

您可以在不使用 Throttler 之类的响应式编程的情况下进行去抖动和节流,

import Throttler

// advanced debounce, running a first task immediately before initiating debounce.

for i in 1...1000 {
    Throttler.debounce {
        print("debounce! > \(i)")
    }
}

// debounce! > 1
// debounce! > 1000


// equivalent to debounce of Combine, RxSwift.

for i in 1...1000 {
    Throttler.debounce(shouldRunImmediately: false) {
        print("debounce! > \(i)")
    }
}

// debounce! > 1000

Throttler 还可以进行高级去抖动,在启动去抖动之前立即运行第一个事件,Combine 和 RxSwift 默认没有。

您可以,但您可能需要自己进行复杂的实现。

【讨论】:

    【解决方案2】:

    在 Swift 4 中使用 DispatchWorkItem!

    // Add a searchTask property to your controller
    var searchTask: DispatchWorkItem?
    
    
    // then in your search bar update method
    
    // Cancel previous task if any
    self.searchTask?.cancel()
    
    // Replace previous task with a new one
    let task = DispatchWorkItem { [weak self] in
        self?.sendSearchRequest() 
    }
    self.searchTask = task
    
    // Execute task in 0.75 seconds (if not cancelled !)
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.75, execute: task)
    

    希望对你有帮助!

    【讨论】:

    【解决方案3】:

    您的错误是因为您可能忘记了 #selector() 部分。

    它应该是这样的:

    func searchBar() { 
        NSObject.cancelPreviousPerformRequests(withTarget: self,    
                                               selector: #selector(self.getSearch(completed:searchString:)), 
                                               object: nil) 
    
        perform(#selector(self.getSearch(completed:searchString:)), 
                with: nil, afterDelay: 0.5) }
    

    您收到错误是因为您没有在 #selector 中包含您的函数

    现在,至于参数,这里有一个函数:

    perform(#selector(getSearch:completion:searchString), with: <some completion>, with: "search string")
    

    【讨论】:

    • 如果我想添加时间间隔是不可能的:(
    • 你可以这样做。但是,如果你注意到自动完成,有一个函数有 timeInterval,除了它只有一个参数可以把它放在你的参数中。我的想法是,您可以扩展类以添加更多参数,但我觉得这有点太多了。也许你应该问另一个关于这个特定问题的问题:)
    • 您的回答对于这个问题是正确的!我打开另一个!
    猜你喜欢
    • 2011-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    相关资源
    最近更新 更多