10

This works

 func startTimer () {
    batchTimer = NSTimer.scheduledTimerWithTimeInterval(batchIntervalSeconds, target: self, selector: #selector(Requester.performRemoteRequests), userInfo: nil, repeats: false)

}

This doesn't

func startTimerInBlock () {
    let urlRequest = NSMutableURLRequest(URL: NSURL(string: "google.com")!, cachePolicy: .ReloadIgnoringLocalCacheData , timeoutInterval: 30)
    urlRequest.HTTPMethod = "GET"
    let session = NSURLSession(configuration: NSURLSessionConfiguration.ephemeralSessionConfiguration())
    let task = session.dataTaskWithRequest(urlRequest) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
        //check there is a response and that it is an http response
        self.batchTimer = NSTimer.scheduledTimerWithTimeInterval(self.batchIntervalSeconds, target: self, selector: #selector(CNVRRequester.performRemoteRequests), userInfo: nil, repeats: false)

    }
    task.resume()
}

Does anybody know why a timer called within a block does not fire?

Daniel K
  • 1,119
  • 10
  • 20

1 Answers1

33

Simple fix, place the self.startTimer code inside a dispatch_block

 DispatchQueue.main.async {
        self.startTimer()
 }

That should fix it.

Edit for explanation

Timers require an active run loop. When you initialize it on main thread, will automatically use main run loop. If you want to run it from a background thread, then you have to attach it to that threads run loop. Example

DispatchQueue.global(qos: .background).async {
    let timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: selector(fireTimer), repeats: false)
    let runLoop = RunLoop.current
    runLoop.add(timer, forMode: .defaultRunLoopMode)
    runLoop.run()
  }

However, if you want to make sure it just runs from the main thread, just start it from a dispatch main closure and it will ensure it will run the main thread.

Edit: Updated for Swift 3

Edit 2: Updated to show background timer answer in line with Phil Mitchells comment

AdamM
  • 4,400
  • 5
  • 49
  • 95
  • 1
    Actually, you can run a timer on background thread, but it takes [extra steps](http://danielemargutti.com/2018/02/22/the-secret-world-of-nstimer/) – Phil Mitchell May 20 '18 at 02:26