So i have this function that should upload some data of a recording every 15 minutes to backend. This should happen even if the user put the app in background. And therefor the Timer.schedule
doesn't work. Hence i figured out i need to put this on a dispatchQueue
code seen below:
while Date(timeIntervalSinceNow: 86400).compare(Date(timeIntervalSinceNow: incrementer)) == .orderedDescending {
incrementer += 900
DispatchQueue.main.asyncAfter(deadline: .now() + incrementer, execute: {
DispatchQueue.main.async {
self.viewModel.upload(data: self.audioRecorder.url, filePath: self.audioRecorder.url)
self.audioRecorder.stop()
self.fileIncrementer += 1
self.startRecording()
}
})
}
This how ever cause a problem when i cancel the task in advance by pressing stop button and presenting the next viewController
this dispatchQueue just keep processing.
What can be done is to throw in:
if var topController = UIApplication.shared.keyWindowInConnectedScenes?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
if (topController as? UINavigationController) != self.navigationController {
print("cought")
return
}
}
Which would stop it if i were in another VC, but if i then enter a new session, i will have double events. So how do i do this in a nice way?
... when ... pressing stop button ... this is
dispatchQueue
just keep processing
Yep, this is precisely why you shouldn’t use this multiple asyncAfter
pattern. (Plus, you may eventually run into timer coalescing problems.) The Timer
is the right way to do this.
So i have this function that should upload some data of a recording every 15 minutes to backend. This should happen even if the user put the app in background.
This is the problem. Neither Timer
nor asyncAfter
can solve this problem.
I infer that you’ve concluded that you can accomplish this with asyncAfter
, but you can’t. Perhaps you were testing this process while running the app attached to the debugger, which artificially keeps the app running in the background. But try it on a device, not attached to the debugger, and you’ll find that the app does not continue to run when the user leaves the app. This asyncAfter
technique will not accomplish what you want.
The exception here is if your app has asked for one of the background capabilities (e.g. VOIP, music, navigation, etc.). But if the app is destined for the App Store, Apple is quite diligent in rejecting apps that request background services for unapproved purposes. This sort of constant background operation kills batteries in the matter of hours, so Apple is looking after the best interests of its user base.
So, bottom line, if your app has a background execution capability, a Timer
is the way to do this periodic process. And if the app doesn’t have a background execution capability, neither Timer
nor any GCD calls will do the job.