iOS path · Living with the system · Topic 8 of 11

Background execution limits

Not started

Once an app leaves the screen, iOS suspends it within moments. That is deliberate: battery life and memory belong to whatever the person is using now. Instead of letting apps run freely, iOS offers a set of narrow, system-scheduled ways to get time in the background, and it decides when (and whether) each request is honoured.

Why it matters: There is no way to keep an ordinary app running in the background. Designs that assume one, like polling a server every minute, don't work on iOS.

  1. 1The system decides

    You request background time; iOS grants it based on battery, network, usage patterns and how you behaved last time.

  2. 2Pick the right tool

    Finish a task, refresh content, do heavy maintenance, transfer files, or get woken by a push: each has its own API.

  3. 3Always have an exit

    Every grant has an expiration handler. Stop cleanly and mark the task complete, or the system ends your app.

1

How it works

The explanation, with examples you can run.

The menu

  • Finish what you started: beginBackgroundTask(withName:expirationHandler:) buys a short extension to complete work in progress, such as saving a file or sending a message. Call it before leaving the foreground and balance it with endBackgroundTask(_:).
  • Refresh content: BGAppRefreshTask runs briefly (Apple documents up to 30 seconds) at a time iOS predicts is useful, often shortly before the person usually opens your app.
  • Heavy maintenance: BGProcessingTask can run for minutes, but only while the device is idle, and can require power or network. Good for database clean-up, ML training, large syncs.
  • Long jobs the user started: BGContinuedProcessingTask (new in iOS 26) starts from a user action, such as an export, and may continue after the app is backgrounded, with progress shown by the system so the person can cancel it.
  • Transfers: background URLSession uploads and downloads (see networking).
  • Woken by your server: background push notifications (see push).
  • Declared modes: audio playback, navigation, VoIP and Bluetooth accessories keep running under their own UIBackgroundModes, and are reviewed for real use.

Scheduling a refresh

Each task identifier must be listed under BGTaskSchedulerPermittedIdentifiers in Info.plist, with the matching background mode (fetch for refresh, processing for processing). In SwiftUI the handler is a scene modifier:

@mainstruct NewsApp: App {    var body: some Scene {        WindowGroup { ContentView() }            .backgroundTask(.appRefresh("com.example.news.refresh")) {                scheduleRefresh()                   // one-off: book the next one                await Headlines.shared.refresh()    // cancelled if time runs out            }    }} func scheduleRefresh() {    let request = BGAppRefreshTaskRequest(identifier: "com.example.news.refresh")    request.earliestBeginDate = .now.addingTimeInterval(30 * 60)  // not before; maybe much later    try? BGTaskScheduler.shared.submit(request)}

In UIKit you register a launch handler with BGTaskScheduler.shared.register(forTaskWithIdentifier:using:launchHandler:) before launch finishes, set the task's expirationHandler, and call setTaskCompleted(success:) when done. In SwiftUI the task completes when your closure returns, and running out of time cancels it.

Why it is this strict, and what to do about it

Background time is a budget the system spreads across all apps. Apps the person rarely opens get less; apps that finish quickly and report completion are treated better; a force-quit app gets nothing until it is opened again. Treat every background grant as a bonus:

  • Make work resumable and idempotent, so being cut off halfway is harmless.
  • Do the essential part first (save, then upload; fetch headlines, then images).
  • When the server knows something changed, send a push instead of polling.
  • Test with Xcode's debugger commands for simulating task launch; on a real device, background tasks almost never run on the schedule you expect.
2

Check yourself

3 questions. Get them all right to finish this topic.

  1. 1.Your app needs to finish saving a large draft when the user leaves it. What should you use?
  2. 2.You schedule a BGAppRefreshTaskRequest with earliestBeginDate set to 15 minutes from now. When does it run?
  3. 3.What happens to a running BGProcessingTask when the person picks up the phone and starts using it?

0 of 3 right so far. Get all three to finish this topic.