Skip to content

Instantly share code, notes, and snippets.

@tarangpatel
Last active March 28, 2020 17:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tarangpatel/46e7aabfb790e69f2f21781a44a78390 to your computer and use it in GitHub Desktop.
Save tarangpatel/46e7aabfb790e69f2f21781a44a78390 to your computer and use it in GitHub Desktop.
[Throttling] #throttling #SearchBar
import UIKit
public class SearchBar: UISearchBar, UISearchBarDelegate {
/// Throttle engine
private var throttler: Throttler? = nil
/// Throttling interval
public var throttlingInterval: Double? = 0 {
didSet {
guard let interval = throttlingInterval else {
self.throttler = nil
return
}
self.throttler = Throttler(seconds: interval)
}
}
/// Event received when cancel is pressed
public var onCancel: (() -> (Void))? = nil
/// Event received when a change into the search box is occurred
public var onSearch: ((String) -> (Void))? = nil
public override func awakeFromNib() {
super.awakeFromNib()
self.delegate = self
}
// Events for UISearchBarDelegate
public func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
self.onCancel?()
}
public func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
self.onSearch?(self.text ?? "")
}
public func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
guard let throttler = self.throttler else {
self.onSearch?(searchText)
return
}
throttler.throttle {
DispatchQueue.main.async {
self.onSearch?(self.text ?? "")
}
}
}
}
// Throttler.swift
//
// Created by Daniele Margutti on 10/19/2017
//
// web: http://www.danielemargutti.com
// email: hello@danielemargutti.com
//
// Updated by Ignazio Calò on 19/10/2017.
import UIKit
import Foundation
public class Throttler {
private let queue: DispatchQueue = DispatchQueue.global(qos: .background)
private var job: DispatchWorkItem = DispatchWorkItem(block: {})
private var previousRun: Date = Date.distantPast
private var maxInterval: Int
init(seconds: Int) {
self.maxInterval = seconds
}
func throttle(block: @escaping () -> ()) {
job.cancel()
job = DispatchWorkItem(){ [weak self] in
self?.previousRun = Date()
block()
}
let delay = Date.second(from: previousRun) > maxInterval ? 0 : maxInterval
queue.asyncAfter(deadline: .now() + Double(delay), execute: job)
}
}
private extension Date {
static func second(from referenceDate: Date) -> Int {
return Int(Date().timeIntervalSince(referenceDate).rounded())
}
}
// value to search for an interval >= 0.5 seconds.
searchBar.throttlingInterval = 0.5
// Receive events for search
searchBar.onSearch = { text in
if text.length == 0 { // user tapped the 'X' button
// restore our plain list without search filter
} else if textToSearch.length > MIN_CHARS_TO_SEARCH {
// A valid search (where length > MIN_CHARS_TO_SEARCH) must be
// performed.
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment