Background tasks in iOS

Kapil Choubisa
4 min readApr 5, 2022

--

Almost two years back, while working on an interesting client project, we were implementing a offline sync solution. Application was receiving data from a bluetooth enabled device and that data was inserted in local database. Later, the data should be uploaded to the server using a POST api. On successful upload of that data, we were suppose to mark a flag in our local database.

In order to explain the problem, let me show (in below diagram) the application states quickly.

Note: BecomeActive and ResignActive are not considered as this diagram is intended to show states and not the lifecycle methods.

With the help of above diagram, we know that application can perform flawlessly while in foreground. However, when user press home button, application enters in background and then developers need to write additional code to take things in their hands.

Problem

As mentioned earlier, our team had situation to make sure that each API call which get initiated should be completed and update database, even if application is moved to the background.

iOS normally allows your application to run in background state for 10 seconds and later it move to suspended state. The suspended state means that application is idle. Not killed but unable to perform any activity unless it is moved back to foreground or background state.

Generally, 10 seconds should be good enough for completing any API call for modern applications as API response time these days is in milliseconds. However, we wanted to delay the suspension of application and get the maximum background time or at least till our task is done.

Application Background Task

The UIBackgroundTask tells OS that application is performing a background activity and should delay the suspension until the task is completed or expired. This generally gives you 30 seconds (may change in OS upgrades, few years back it was 180 seconds).

You should finish your task within the extra time you get.

How to do it?

You can call beginBackgroundTask on UIApplication’s shared instance. This will provide you an UIBackgroundTaskIdentifier object. You should keep track of this object and call endBackgroundTask in the expiration handler.

The above code will end the task once the background task expires i.e roughly around 30 seconds. Now what if your task was actually completed at 15th second? This still keep your application in background for 30 seconds. Now that’s not a good tenant behaviour on a device.

So you should keep track of the identifier and call endBackgroundTask method once your task is completed i.e 15th second and let application suspend.

A task created should always end.

If you don’t end a task, this can lead the watchdog kill your application unexpectedly and that is going to be a crash for you. Definitely you don’t want this.

It is up to you to decide when to end the task. As mention above, you can end it once the desired job is completed or in the expiration block. I suggest to do it at both the places. Something like:

Create one task for one job

I have seen many developers using the beginBackgroundTask method in applicationDidEnterBackground lifecycle hook. This definitely work but don’t give you control over ending the task when the intended job is completed.

So, if you are calling multiple APIs or other operation, which you want to make sure that gets enough time, you should call the beginBackgroundTask method. You should also keep track of that task identifier, so that you can end it once job is done. Remember the watchdog is watching you.

Can I get unlimited time?

Or let me reframe it by asking “can I fool the OS?”. You might have an idea or may be not but I had it. I thought of calling the beginBackgroundTask method from the expiry block of the previous one to keep on getting 30 seconds. See below code:

It doesn’t work that way. You try it with recursive or in a loop or as many as background task, there is a fix time you will get from OS and it won’t exceed from that. E.g. if you create one task as soon as you enter in background and you got 30 seconds, after 10 seconds you create another task and you will not get more than 20 seconds now because 10 seconds are already passed since application went in background.

How to bring application back from suspended state?

This could definitely be the next question and the easiest answer is when user bring the application back in foreground. However, there are other ways by which application can come out of suspended state and be in background state without user’s intervention.

  • Events from BackgroundModes specified in info.plist. E.g. If application is listening to location events, when location update event is delivered, OS put application in background mode and you can get up to 30 seconds using background task.
  • By sending Silent push notification from application server.

Conclusion

  • Get up to 30 seconds while application is in background by calling beginBackgroundTask .
  • Can have multiple task created associated with each job to be done.
  • Even by creating multiple tasks the background time will not exceed 30 seconds.
  • A task created should end by calling endBackgroundTask to avoid watch dog killing the application.
  • A task should end as soon as the relevant job is done.

--

--