Abdulmajed
Abdulmajed

Reputation: 19

Background threading for longer tasks

I built an iOS app with the SwiftUI framework. I want to run a task for a long period of time depending on whether the user is running or not. So I used the Combine framework to start and stop some processes related to running activity using a background thread with quality of service as .background. However, I noticed that sometimes the process of starting and stop gets delayed or killed. I'm okay with delaying the process but I'm not okay with it being killed.

I wonder how can I solve this? Because if you use google maps and you hit start navigation for your location. The process doesn't get killed. So there must be a way to start the process on the background thread for a longer period of time. I just don't know-how. Any Ideas?

        self.activaity.$running
        .subscribe(on: self.BackgroundQueue)
        .receive(on: self.BackgroundQueue)
        .removeDuplicates(by: {$0 == $1})
        .sink(receiveValue: { [self] value in
                if value {
                        self.start()
                }
                else{
                        self.stop()
                }
        })
        .store(in: &self.cancellables)   


func start() {
    self.persistMetaData()
    self.persist()
    self.sensorManager.startUpdates()
   }
        

Thanks

Upvotes: 0

Views: 1391

Answers (1)

Duncan C
Duncan C

Reputation: 131408

In iOS the term background can mean 2 different things: Running on a background thread, or when your app is no longer the front-most app but is still getting processing time.

The two are only loosely related. Starting a task running on a background thread is not the same thing as setting up your app to keep getting CPU time after the user switches it to the background or locks the device.

A background thread is a separate execution path through your code that is usually (but not always) run on a different processor and usually at the same time as your primary thread. It's like you have two cooks in a kitchen, both cooking different dishes. They have to share the same equipment and supplies, and if cook one leaves a mess, or steals ingredients cook two one has prepared, it can screw up cook two. Similarly, multiple threads have to be careful not to access the same memory at the same time without a way to synchronize that access, or talk to the hardware systems at the same time.

In order to understand the other meaning for background, we need to talk about how the OS manages apps. If your app is the frontmost app, it runs in the foreground. Normally, if the user swaps apps, you get a notification that you are being suspended. You are expected to stop running timers an save your app's data. You can ask for extra time to keep running in the background, but that is typically only about 3 minutes max. (In this sense of the word background, it means your app keeps doing things like downloading files or recording GPS readings while another app is on the screen and the user is interacting with it.)

After possibly running for a short time in the background, your app is switched to the "suspended" state. In that state it does not get any processor time. (None of your app's threads get any processor time.) Once in the suspended state, it can be terminated (removed from memory and killed) at any time without further notice. If it's killed, all of it's threads are killed, and all of its state data in memory is lost. That's why you should save your app state when you are told you are about to be suspended.

A very limited number of app types (turn-by-turn navigation apps, streaming music apps, and one or two others) are allowed to run indefinitely in the background. (I believe HealthKit apps are another of those app types that are allowed to run continuously in the background, although I've never looked at HealthKit in any detail.) Apple limits the apps that can run in the background because the CPU takes a lot more power when it is running at full speed, and more power to get any CPU time at all. Apple only allows very specific apps to run in the background, and only when the user authorizes them to do so. That lets Apple (and the user) limit power consumption and conserve battery life. Apps running in the background can also slow down the performance of the foreground app, although the hardware can throttle the background app to prevent that. Your example, Google Maps, is a turn-by-turn navigation app. It declares itself as such, and before iOS lets it keep running in the background the user has to grant it permission to do so.

Ignoring those types of apps and getting back to your app:

If the user switches back to your app while it is suspended, it picks up right where it left off, with all its state variables sill intact and the foreground thread and any background threads that were running start getting CPU time again.

When your app is terminated, any background threads are killed along with it. When it is re-launched, you will have to start any background threads that you want to run over again.

Starting tasks on a background thread will not keep your app running when the user switches to another app. Again, the two uses of the term background mean quite different things.

Upvotes: 2

Related Questions