
What is Throttling all about, it’s a process responsible for regulating the rate at which application processing is conducted (doesn’t matter statically or dynamically). Wikipedia
A very common use in iOS, when you have a search bar which takes input from user and sends off a request for search results every time. For a long query it may cause lot of requests to be sent on server to process (performance will be different for slow vs fast typing user & also depends on internet connection).
Another use case that I faced today is to log an impression when user sees the TableViewCell. I found and interesting example on Github. I created an extension for this to make use of it everywhere.
Create a protocol.
protocol Throttable {
func perform(with delay: TimeInterval,
in queue: DispatchQueue,
block completion: @escaping () -> Void) -> () -> Void
}
Provide the default implementation using the extension.
extension Throttable {
func perform(with delay: TimeInterval,
in queue: DispatchQueue = DispatchQueue.main,
block completion: @escaping () -> Void) -> () -> Void {
var workItem: DispatchWorkItem?
return {
workItem?.cancel()
workItem = DispatchWorkItem(block: completion)
queue.asyncAfter(deadline: .now() + delay, execute: workItem!)
}
}
}
Responsibility of this function is just to return a function, when you call the returned function.
- It cancels the exiting
workItem
if exists (magical Optional). - Creates a new
DispatchWorkItem
with thecompletion
block. - And the queue calls the
workItem
with givendelay
.
And that’s how it works, Just conforms the Throttable
protocol wherever you want.
class UserInputHandler: Throttable {
let triggerAPI = perform(with: 1.0) {
print("Fetch Search Result")
}
func didReceiveInput() {
triggerAPI()
}
}
Here is an easy example to integration it with UIViewController
class SearchViewController: UIViewController, Throttable {
@IBOutlet weak var searchTextField: UITextField!
lazy var triggerAPI = perform(with: 1.0) { [weak self] in
guard let searchText = self?.searchTextField.text, !searchText.isEmpty else {
return
}
print("API Request to fetch result for \(searchText)")
}
}
extension SearchViewController: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
triggerAPI()
return true
}
}
Thanks for reading
Find more Swift Tips and Tricks on Github.