i am trying to do an application which can make a timer run in background.
here\'s my code:
let taskManager = Timer.scheduledTimer(timeInterval: 10,
As others pointed out, Timer cannot make a method run in Background. What you can do instead is use while loop inside async task
DispatchQueue.global(qos: .background).async {
while (shouldCallMethod) {
self.callMethod()
sleep(1)
}
}
Timer won't work in background. For background task you can check this link below...
https://www.raywenderlich.com/143128/background-modes-tutorial-getting-started
This works. It uses while loop inside async task, as suggested in another answer, but it is also enclosed within a background task
func executeAfterDelay(delay: TimeInterval, completion: @escaping(()->Void)){
backgroundTaskId = UIApplication.shared.beginBackgroundTask(
withName: "BackgroundSound",
expirationHandler: {[weak self] in
if let taskId = self?.backgroundTaskId{
UIApplication.shared.endBackgroundTask(taskId)
}
})
let startTime = Date()
DispatchQueue.global(qos: .background).async {
while Date().timeIntervalSince(startTime) < delay{
Thread.sleep(forTimeInterval: 0.01)
}
DispatchQueue.main.async {[weak self] in
completion()
if let taskId = self?.backgroundTaskId{
UIApplication.shared.endBackgroundTask(taskId)
}
}
}
}
If 1 or 2 seconds threshold is acceptable this hack could be helpful.
UIApplication.didEnterBackgroundNotification
UIApplication.willEnterForegroundNotification
Stop Timer and Backup Date() on didEnterBackground.
Add Date() to the Backup date on willEnterForegraound to achieve total time.
Start Timer and Add total date to the Timer.
Notice: If user changed the date time of system it will be broken!
You dont really need to keep up with a NSTImer object. Every location update comes with its own timestamp.
Therefore you can just keep up with the last time vs current time and every so often do a task once that threshold has been reached:
if let location = locations.last {
let time = location.timestamp
guard let beginningTime = startTime else {
startTime = time // Saving time of first location time, so we could use it to compare later with subsequent location times.
return //nothing to update
}
let elapsed = time.timeIntervalSince(beginningTime) // Calculating time interval between first and second (previously saved) location timestamps.
if elapsed >= 5.0 { //If time interval is more than 5 seconds
//do something here, make an API call, whatever.
startTime = time
}
}
============== For Objective c ================
create Global uibackground task identifier.
UIBackgroundTaskIdentifier bgRideTimerTask;
now create your timer and add BGTaskIdentifier With it, Dont forget to remove old BGTaskIdentifier while creating new Timer Object.
[timerForRideTime invalidate];
timerForRideTime = nil;
bgRideTimerTask = UIBackgroundTaskInvalid;
UIApplication *sharedApp = [UIApplication sharedApplication];
bgRideTimerTask = [sharedApp beginBackgroundTaskWithExpirationHandler:^{
}];
timerForRideTime = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(timerTicked:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:timerForRideTime forMode: UITrackingRunLoopMode];
Here this will work for me even when app goes in background.ask me if you found new problems.