Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect when user stopped / paused typing in Swift

I've dug around stackoverflow and found the solution which I converted to Swift, it doesn't seem to work and the selector is still being performed.

 func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    self.filter.searchTerm = self.searchBar.text

    NSObject.cancelPreviousPerformRequestsWithTarget(self, selector: "getHints", object: nil)
    NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "getHints", userInfo: nil, repeats: false)
}

Is there a better way to do this in swift? Thanks!

like image 654
Tuan Anh Vu Avatar asked Apr 21 '15 03:04

Tuan Anh Vu


1 Answers

UPDATE 2016/09/01:

We can use NSTimers or (since swift 2.0) NSObject's performSelector and friends.

Aproach 1 : performSelector

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
    replacementString string: String) -> Bool {
    NSObject.cancelPreviousPerformRequests(
        withTarget: self,
        selector: #selector(ViewController.getHintsFromTextField),
        object: textField)
    self.perform(
        #selector(ViewController.getHintsFromTextField),
        with: textField,
        afterDelay: 0.5)
    return true
}

func getHintsFromTextField(textField: UITextField) {
    print("Hints for textField: \(textField)")
}

Approach 2: NSTimer

var timer: NSTimer? = nil

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
    replacementString string: String) -> Bool {
    timer?.invalidate()
    timer = Timer.scheduledTimer(
        timeInterval: 0.5,
        target: self,
        selector: #selector(ViewController.getHints),
        userInfo: ["textField": textField],
        repeats: false)
    return true
}

func getHints(timer: Timer) {
    var userInfo = timer.userInfo as! [String: UITextField]
    print("Hints for textField: \(userInfo["textField"])")
}

Note I am passing the textField to delayed functions. It is not always required but it could make your life easier when textField is not easy to access or when dealing with various text fields.

How NSTimer approach is different from performSelector?

When you call performSelector the target is retained (in swift the target is always self) but when you use NSTimer the target is NOT retained. This means, if you use NSTimers, you have to make sure target (in this case self) is alive by the time the timer fires. Otherwise the a crash will occur.

(BTW: performSelector uses NSTimer internally 😀 )

If you are interested in GCD timers this gist a good place start: maicki/TimerWithGCD.md

like image 146
nacho4d Avatar answered Oct 15 '22 00:10

nacho4d