21

Description:

I'm currently using the following code to see if the user has stopped typing in the searchBar. I would like to cancel it everytime the user immediately starts typing after 0.5 seconds.

Code:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    // your function here
}

Question:

How do I cancel DispatchQueue.main.asyncAfter if the user starts typing again in Swift3 ?

What I've tried:

I previously tried implementing :

NSObject.cancelPreviousPerformRequests(withTarget: self)
self.perform(Selector(("searchForText:")), with: searchString, afterDelay: 0.5)

However the delay does not seem to work properly.

More code:

//In class SearchViewController: UITableViewController, UISearchResultsUpdating
func updateSearchResults(for searchController: UISearchController) {
    let searchString: String = searchController.searchBar.text!

    //This is what I previously tried.. which doesn't work...
    //NSObject.cancelPreviousPerformRequests(withTarget: self)
    //self.perform(Selector(("searchForText:")), with: searchString, afterDelay: 0.5)

    //A struct with the first example code shown above.
    Utils.Dispatch.delay(secondsToDelay: 1){
        print("1 second has passed ! " + searchString)
    }
}
kemicofa ghost
  • 16,349
  • 8
  • 82
  • 131
  • try this http://stackoverflow.com/questions/39744291/swift-2-to-3-migration-dispatch-get-global-queue/39744608#39744608 if it is working or not – JAck Oct 04 '16 at 10:11
  • I recommend to use you **NSOperation**, you will be able to add dependency among operations and re-use, cancel or suspend them. – Ahmad F Oct 04 '16 at 10:36
  • I found the solution, I'll post it as an answer when I'm completely sure it works. – kemicofa ghost Oct 17 '16 at 07:10
  • Did you verify your solution yet? I'm on the same problem right now... – eobet Nov 27 '16 at 15:57
  • 1
    EDIT: Here apparently... http://stackoverflow.com/a/39684520/2387365 – eobet Nov 27 '16 at 16:39
  • @eobet I haven't had time to completely test it, been working on another section of the project atm. I'll get to it soon though. Thanks for the link, I'll take a look at it. Did that solution work for you? – kemicofa ghost Nov 28 '16 at 12:56
  • **The linked solution worked for me.** And it should work for everyone using Swift 3. Could have saved me a couple minutes if I found this link earlier. – Alain Stulz Feb 28 '17 at 23:14

1 Answers1

4

For those that have time to test code, I'll post my current solution that is untested. When I have time to try it, I'll edit the post.

private var operationQueue: OperationQueue!
private var mainAsyncQueue: DispatchQueue?


override func viewDidLoad() {
    print("ViewDidLoad of SearchViewController called")

    self.operationQueue = OperationQueue()
    self.currentTime = DispatchTime.now()

}
// MARK: UISearchResultsUpdating

func updateSearchResults(for searchController: UISearchController) {
    let searchStringRaw: String = searchController.searchBar.text!
    let searchString = searchStringRaw.trimmingCharacters(in: .whitespacesAndNewlines)
    guard searchString.characters.count > 0 else {
        return
    }

    print("Search string: \(searchString)")
    self.operationQueue.cancelAllOperations()
    //Put this in Utils.Dispatch.Delay
    self.mainAsyncQueue = DispatchQueue(label: "search.operation." + String(describing: DispatchTime.now()), qos: .default, attributes: DispatchQueue.Attributes.concurrent)

    let time = DispatchTime.now()
    self.currentTime = time

    self.mainAsyncQueue!.asyncAfter(deadline: time + 1){
        guard self.currentTime == time else {
            return
        }

        let tempOperation = BlockOperation(block:{

            if let nsurl: URL = Utils.Url.generate(Constants.Url.Search, options: "&p=1&n=20&q="+searchString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!){
                //Download data and handle response

            } else {
                print("Something went wrong...")
            }


        })
        self.operationQueue.addOperation(tempOperation)
    }

}
kemicofa ghost
  • 16,349
  • 8
  • 82
  • 131
  • 1
    Thank, kemicofa. On my use I had to use `DispatchQueue.main.async {}` inside the blockOperation to run my code because it was an autolayout animation. Great work! – Quaggie Jan 09 '19 at 12:58
  • For the lost souls that need this for something simpler, this might be of your interest: https://stackoverflow.com/questions/48016111/how-to-stop-a-dispatchqueue-in-swift/48016360 – gabuchan Jul 07 '20 at 18:02