Background Task is an iOS mechanism that allows an application to complete an operation after transitioning to the background. The system allocates limited time (up to 30 seconds) to execute the task, after which the application is forcibly suspended. According to Apple, 2026, using an expiration handler is a mandatory requirement for properly completing a background task.
Key Takeaways
Background Task is a programmatic iOS mechanism that allows an application to extend execution time after transitioning to the background. When a user minimizes the app, the system calls UIApplicationDelegate.applicationDidEnterBackground. If a critical operation is being performed at that moment (saving data, sending a request), the application can request additional time via beginBackgroundTask.
Without using Background Task, the application is forcibly suspended within 3–5 seconds after going into the background. All incomplete operations are interrupted: data is not saved, network requests are aborted, states are lost. Background Task gives the application up to 30 seconds to properly complete these operations.
beginBackgroundTask appeared in iOS 4.0 — the first release supporting multitasking. Before iOS 4, the application was completely terminated when the Home button was pressed. iOS 7 introduced Background Fetch and URLSession background configuration. Starting with iOS 13, Apple recommends BGTaskScheduler for new projects, but beginBackgroundTask remains relevant for short-term operations.
beginBackgroundTask is a UIApplication method that registers a task and returns a unique UIBackgroundTaskIdentifier. The system increases the background execution timer. When time expires, the expiration handler is called, after which the application must call endBackgroundTask(identifier:) to properly complete the task.
Step 1 — the application receives the didEnterBackground notification. Step 2 — beginBackgroundTask(expirationHandler:) is called. Step 3 — the critical operation (saving, network request) is performed. Step 4 — upon completion, endBackgroundTask(identifier:) is called. If the operation does not complete within 30 seconds — the system calls the expiration handler, and the application must finish the task immediately.
var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
func startBackgroundTask() {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
// Expiration handler
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
}
func finishBackgroundTask() {
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
The backgroundTimeRemaining property returns the number of seconds remaining before the background task is forcibly terminated. The value decreases in real time. If the application is not in the background — it returns DBL_MAX. Use this property to adapt behavior: when less than 5 seconds remain, interrupt long-running operations and save progress.
An application can register multiple Background Tasks simultaneously. Each task gets its own identifier. The total execution time is cumulative — if 3 tasks are registered, the application can get up to 90 seconds. However, the system may terminate the application earlier if resources are exhausted or the battery limit is exceeded.
Expiration handler is a block of code that the system calls when the allocated background task time expires. Having an expiration handler is a mandatory Apple requirement. Without it, the application may be forcibly terminated by the system and data may be lost.
The expiration handler must perform minimal actions to save the application state: save current data to persistent storage, call endBackgroundTask with the corresponding identifier, and set the identifier to .invalid. Inside the expiration handler, it is forbidden to start new long-running operations — execution time is limited to 1–2 seconds.
func handleExpiration() {
// Saving execution progress
saveProgressToUserDefaults()
// Canceling active network requests
currentTask?.cancel()
// Finishing Background Task
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
// Registration with expiration handler
backgroundTaskID = UIApplication.shared.beginBackgroundTask(
withName: "SaveDocument",
expirationHandler: handleExpiration
)
The most common mistake is not calling endBackgroundTask inside the expiration handler. In this case, the system continues to consider the task active, the application does not transition to the Suspended state, and the battery drains. The second mistake is starting long-running operations inside the expiration handler. The system may terminate the application before they complete, and data will be lost.
In the expiration handler, execution time is critically limited — typically less than 1 second. Therefore, inside the handler you cannot perform: complex calculations, network requests, writing large amounts of data to CoreData. Only atomic operations: writing a single key to UserDefaults, setting a state flag, calling endBackgroundTask.
Let’s review a complete Background Task implementation for saving a document when the app goes into the background. The example includes task registration, performing an operation with remaining time checking, and proper completion via endBackgroundTask.
When going into the background, the application initiates saving a large document. Background Task provides up to 30 seconds for the operation. If time expires — the expiration handler saves intermediate results. After saving completes, endBackgroundTask is called to release resources.
class DocumentManager {
private var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
func saveDocumentInBackground(document: Document) {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
self.saveProgress(document)
self.endBackgroundTask()
}
DispatchQueue.global().async {
document.save()
self.endBackgroundTask()
}
}
private func endBackgroundTask() {
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
}
Network requests in the background require special attention — the expiration handler may interrupt the request before receiving a response. Use URLSession with dataTask and check backgroundTimeRemaining before sending. If less than 5 seconds remain — postpone sending until the next app wake-up.
func sendCriticalData(data: Data) {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
// Saving data for resending
saveForRetry(data)
self.endBackgroundTask()
}
let task = URLSession.shared.dataTask(with: request) { _, _, error in
if error != nil {
saveForRetry(data)
}
self.endBackgroundTask()
}
task.resume()
}
For long-running operations, monitor UIApplication.shared.backgroundTimeRemaining. If the value drops below a threshold (10 seconds), interrupt the current operation and start saving intermediate results. This allows proper completion before the expiration handler is forcibly called.
Background Task is a powerful mechanism, but its improper use leads to battery and performance issues. Following Apple’s recommendations and proven community practices will help avoid common mistakes and ensure stable application operation.
Complete the Background Task as quickly as possible. Each second of background execution drains battery power. Optimal time — less than 5 seconds. If the operation takes longer — consider using BGTaskScheduler or Background Modes. Do not artificially extend the task through beginBackgroundTask calls without real need.
Store UIBackgroundTaskIdentifier as a class or struct property. Never pass it as a global variable — this leads to conflicts with multiple tasks. Set the identifier to .invalid after calling endBackgroundTask to prevent double completion.
In Xcode Simulator, switch the app to the background via the Home button (Command + Shift + H). Use Debug — Simulate Background Fetch for testing background wake-up. To emulate time expiration, set the Environment Variable BACKGROUND_TASK_SIMULATE_EXPIRATION = YES — the expiration handler will be called within 5 seconds.
// Checking remaining time before starting the operation
let remaining = UIApplication.shared.backgroundTimeRemaining
guard remaining > 10.0 else {
// Not enough time — postpone the task
scheduleForNextLaunch()
return
}
// Executing the operation with time control
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
saveProgress()
self.endBackgroundTask()
}
The expiration handler captures self — this can create a retain cycle if backgroundTaskID is stored as a property of the same object. Use [weak self] in the closure or store the identifier separately. A retain cycle leads to a memory leak — the object will not be released until the application terminates.
With the release of iOS 13, Apple introduced BGTaskScheduler — a modern replacement for the old Background Task API. Both mechanisms solve similar tasks, but BGTaskScheduler provides more control and flexibility. Understanding the differences will help choose the right tool for a specific scenario.
| Characteristic | Background Task | BGTaskScheduler |
|---|---|---|
| iOS Version | 4.0+ | 13.0+ |
| Max Time | 30 seconds | 30 s / 10 min (processing) |
| Initiation | didEnterBackground | Scheduling + system |
| Execution Guarantee | Only when entering background | At any convenient system time |
| Expiration handler | Yes, mandatory | Yes, via task.expirationHandler |
| Internet | Required at launch | Available via requiresNetworkConnectivity |
| Charging | Not required | Optional for processing |
beginBackgroundTask is suitable for short-term operations that need to be performed immediately when going into the background: saving state, completing a network request, caching data. The API is simple and does not require Info.plist configuration or identifier registration. Ideal for operations that take less than 10 seconds.
BGTaskScheduler is suitable for tasks that can be performed at any convenient time: periodic synchronization, cache cleanup, widget updates. The system itself selects the optimal time considering user behavior and battery state. For long-running operations (up to 10 minutes), use BGProcessingTask.
Both APIs can be used in the same application. Background Task — for immediate operations when going into the background (saving a draft). BGTaskScheduler — for scheduled updates (synchronization every 6 hours). Separation of responsibilities ensures proper data preservation and energy-efficient background maintenance.
Frequently Asked Questions
Yes, beginBackgroundTask can be called at any point during application execution. However, system time allocation will only start after transitioning to the background. If the application is in the foreground, calling beginBackgroundTask has no effect — backgroundTimeRemaining returns DBL_MAX, and the task will be activated when going into the background.
If endBackgroundTask is not called, the system continues to consider the application active in the background. After 30 seconds, the expiration handler will be called, but if it also lacks endBackgroundTask — the application stays in memory, draining the battery. In iOS 13+, the system forcibly terminates such an application after 3 minutes.
The standard time is 30 seconds. It can only be extended through Background Modes: Audio (playback), Location (geolocation), Bluetooth (BLE). Or via BGProcessingTask (iOS 13+) — up to 10 minutes with charging and Wi-Fi. beginBackgroundTask itself does not provide a way to increase the limit.
Yes, iPadOS fully supports beginBackgroundTask with the same limitations as iOS. On iPad with Stage Manager, the application may stay in memory longer — the system suspends applications less frequently due to larger RAM. But the 30-second background task limit remains.
Connect the device to Xcode, launch the application, minimize it — system logs will appear in the console. Use sysdiagnose to collect detailed logs: force trigger sysdiagnose from the device (Volume Up + Down + Power). In Xcode Debug Navigator, monitor background task activity.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also