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.

- 798
- 1
- 11
- 22
-
did my answer help you? – Reinier Melian Aug 07 '17 at 20:02
-
@ReinierMelian It works but i ended up doing something different because I didn't wanna create a new textview. – BlueBoy Aug 07 '17 at 20:44
-
ok @BlueBoy good luck then! Thanks for let me know – Reinier Melian Aug 07 '17 at 21:20
-
@BlueBoy, Hi dude, do you solve this problem? can you help me, I have same problem... – Sina Feb 25 '18 at 11:37
2 Answers
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

- 20,519
- 3
- 38
- 55
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).

- 74,769
- 26
- 128
- 150
-
1@BlueBoy : Added more explanation as to what is going on. I like this approach a little more than the timer based approach as I prefer not to use timers and custom classes for response handling. – Kendall Helmstetter Gelner Aug 07 '17 at 03:02