In swift, how can I run some code 1 second after a user stops typing into a textfield? There is textFieldDidChange
but that will run code immediately after a new character is typed.
Try with this custom UITextField
, you need setup a timer to 1 second every time a user put a character in your UITextField
, and invalidate the timer before re-schedule again, I added the action as closure to allow any kind of action, giving full freedom in you implementation
Added Inspectable property for delay customization
import UIKit
@IBDesignable
class AfterOneSecondTextField: UITextField {
@IBInspectable var delayValue : Double = 1.0
var timer:Timer?
var actionClosure : (()->Void)?
override func awakeFromNib() {
super.awakeFromNib()
self.addTarget(self, action: #selector(changedTextFieldValue), for: .editingChanged)
}
func changedTextFieldValue(){
timer?.invalidate()
//setup timer
timer = Timer.scheduledTimer(timeInterval: delayValue, target: self, selector: #selector(self.executeAction), userInfo: nil, repeats: false)
}
func executeAction(){
actionClosure?()
}
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
}
Use it
You only need to set the class, and pass a closure to your desired action in my case is debugPrint but you can do whatever you need
class ViewController: UIViewController {
@IBOutlet weak var tfText: AfterOneSecondTextField!
override func viewDidLoad() {
super.viewDidLoad()
tfText.actionClosure = {
debugPrint("Test")
}
}
This works!, was tested
Hope this helps
What I have done is use a cancelable closure to run code after some delay; that way as the user types the closure keeps getting cancelled, but when they pause long enough or finish the code to search or fetch is actually run after a brief delay.
I used the cancelable closure code from here:
Cancel a timed event in Swift?
Then the code that goes into textFieldDidChange looks like:
fileprivate var delayedSearchClosure : dispatch_cancelable_closure?
open func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if let searchClosure = delayedSearchClosure {
searchClosure(true)
delayedSearchClosure = .none
}
delayedSearchClosure = delayClosure(0.8) { [weak self] in
self?.doSearch(searchText)
self?.delayedSearchClosure = .none
}
}
To explain what is happening here - in the callback for the textfield as the user types, I first terminate the existing closure created to run at a specific time. Then in the next block of code, it makes a new delayedSearchClosure that will execute 0.8 seconds from now and call "doSearch()
", then toss away the closure.
Thus as the user types, closures are being thrown away that no longer matter. Eventually the user will pause or stop typing, at that point the code you want run is actually executed (in this case a search is performed based on the text). This gives you a search form that feels responsive but does not waste time with an added search launched for every character a user types (which can add overhead and start to impact the UI performance).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With