I\'m trying to use a UISearchView
to query google places. In doing so, on text change calls for my UISearchBar
, I\'m making a request to google pla
Despite several great answers here, I thought I'd share my favorite (pure Swift) approach for debouncing user entered searches...
1) Add this simple class (Debounce.swift):
import Dispatch
class Debounce {
private init() {}
static func input(_ input: T,
comparedAgainst current: @escaping @autoclosure () -> (T),
perform: @escaping (T) -> ()) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
if input == current() { perform(input) }
}
}
}
2) Optionally include this unit test (DebounceTests.swift):
import XCTest
class DebounceTests: XCTestCase {
func test_entering_text_delays_processing_until_settled() {
let expect = expectation(description: "processing completed")
var finalString: String = ""
var timesCalled: Int = 0
let process: (String) -> () = {
finalString = $0
timesCalled += 1
expect.fulfill()
}
Debounce.input("A", comparedAgainst: "AB", perform: process)
Debounce.input("AB", comparedAgainst: "ABCD", perform: process)
Debounce.input("ABCD", comparedAgainst: "ABC", perform: process)
Debounce.input("ABC", comparedAgainst: "ABC", perform: process)
wait(for: [expect], timeout: 2.0)
XCTAssertEqual(finalString, "ABC")
XCTAssertEqual(timesCalled, 1)
}
}
3) Use it wherever you want to delay processing (e.g. UISearchBarDelegate):
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
Debounce.input(searchText, comparedAgainst: searchBar.text ?? "") {
self.filterResults($0)
}
}
Basic premise is that we are just delaying the processing of the input text by 0.5 seconds. At that time, we compare the string we got from the event with the current value of the search bar. If they match, we assume that the user has paused entering text, and we proceed with the filtering operation.
As it is generic, it works with any type of equatable value.
Since the Dispatch module has been included in the Swift core library since version 3, this class is safe to use with non-Apple platforms as well.