Created
February 2, 2020 12:19
-
-
Save rafattouqir/f3d076a6f3a99f752a4329ae87c2d889 to your computer and use it in GitHub Desktop.
Simple RxSwift like Throttle functionality added to UISearchBar and UISearchController
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ThrottledSearchController.swift | |
// Created by Daniele Margutti on 10/19/2017 | |
// Updated by RAFAT TOUQIR RAFSUN. | |
import UIKit | |
class ThrottledSearchController: UISearchController{ | |
// Mark this property as lazy to defer initialization until | |
// the searchBar property is called. | |
private lazy var customSearchBar = ThrottledSearchBar() | |
// Override this property to return your custom implementation. | |
override var searchBar: UISearchBar { customSearchBar } | |
} | |
class ThrottledSearchBar: UISearchBar, UISearchBarDelegate { | |
/// Throttle engine | |
private var throttler: Throttler? = nil | |
/// Throttling interval | |
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 | |
var onCancel: (() -> (Void))? = nil | |
/// Event received when a change into the search box is occurred | |
var onSearch: ((String) -> (Void))? = nil | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
self.delegate = self | |
} | |
required init?(coder: NSCoder) { | |
super.init(coder: coder) | |
self.delegate = self | |
} | |
// Events for UISearchBarDelegate | |
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { | |
self.onCancel?() | |
} | |
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { | |
self.onSearch?(self.text ?? "") | |
} | |
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 ?? "") | |
} | |
} | |
} | |
} | |
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: Double | |
init(seconds: Double) { | |
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) -> Double { | |
return Date().timeIntervalSince(referenceDate).rounded() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ViewController.swift | |
// Created by RAFAT TOUQIR RAFSUN. | |
import UIKit | |
class ViewController: UIViewController { | |
fileprivate let searchController: UISearchController = { | |
let searchController = ThrottledSearchController(searchResultsController: nil) | |
(searchController.searchBar as? ThrottledSearchBar)?.throttlingInterval = 0.5 | |
return searchController | |
}() | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
// Do any additional setup after loading the view. | |
self.setupSearchBar() | |
} | |
private func setupSearchBar(){ | |
searchController.searchResultsUpdater = self | |
searchController.obscuresBackgroundDuringPresentation = false | |
searchController.searchBar.placeholder = "Search Here..." | |
self.navigationItem.searchController = searchController | |
self.definesPresentationContext = true | |
(searchController.searchBar as? ThrottledSearchBar)?.onSearch = {(searchText) in | |
if searchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty{ | |
print(searchText) | |
}else { | |
// A valid search (where searchText.count > MIN_CHARS_TO_SEARCH) could be used | |
print(searchText) | |
} | |
} | |
} | |
} | |
extension ViewController: UISearchResultsUpdating { | |
func updateSearchResults(for searchController: UISearchController) { } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment