Swift 3 中的实时搜索限制
Live search throttle in Swift 3
我正在尝试使用 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()
}
}
}
table 视图正在用 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!
P.S。从我发现的另一个答案
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
您的错误是因为您可能忘记了 #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")
使用 DispatchWorkItem Swift 4 !
// 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)
希望对您有所帮助!
- 免责声明:我是一名作家。
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 默认情况下没有。
你可以,但你自己可能需要一个复杂的实现。
我正在尝试使用 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()
}
}
}
table 视图正在用 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!
P.S。从我发现的另一个答案
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
您的错误是因为您可能忘记了 #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")
使用 DispatchWorkItem Swift 4 !
// 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)
希望对您有所帮助!
- 免责声明:我是一名作家。
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 默认情况下没有。
你可以,但你自己可能需要一个复杂的实现。