Background Tasks and Refresh
Schedule background work with BGTaskScheduler.
Background Tasks and Refresh is a free Swift Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Why Background Tasks Exist
iOS aggressively suspends apps to save battery. To do meaningful work while backgrounded — refreshing a feed, processing a download — you schedule it through BGTaskScheduler. The system decides when to run it, balancing your needs against power and usage patterns.
import BackgroundTasks
// You request work; the system schedules it later
// at an opportune moment (charging, on Wi-Fi, etc.)Two Task Types
There are two kinds: BGAppRefreshTask for short, frequent updates (seconds), and BGProcessingTask for longer, heavier work (minutes) like database maintenance, optionally requiring power or network.
import BackgroundTasks
// BGAppRefreshTask -> quick content refresh
// BGProcessingTask -> long maintenance, can require
// external power / networkDeclaring Identifiers
Each task needs a unique identifier you list in Info.plist under BGTaskSchedulerPermittedIdentifiers. Without this declaration, registration fails. Use reverse-DNS style strings.
// Info.plist:
// BGTaskSchedulerPermittedIdentifiers = [
// "com.example.app.refresh",
// "com.example.app.cleanup"
// ]
let ids = "declare every identifier in Info.plist"
_ = idsRegistering a Handler
At launch, register a handler for each identifier with BGTaskScheduler.shared.register. This must happen before the app finishes launching. The handler runs whenever the system later decides to execute the task.
import BackgroundTasks
func registerTasks() {
BGTaskScheduler.shared.register(
forTaskWithIdentifier: "com.example.app.refresh",
using: nil) { task in
handleRefresh(task as! BGAppRefreshTask)
}
}Submitting a Request
Registering only wires up the handler. To actually ask for a run, build a BGAppRefreshTaskRequest, set the earliest begin date, and submit it. The system treats the date as a hint, not a guarantee.
import BackgroundTasks
func scheduleRefresh() {
let request = BGAppRefreshTaskRequest(
identifier: "com.example.app.refresh")
request.earliestBeginDate = Date(
timeIntervalSinceNow: 15 * 60)
try? BGTaskScheduler.shared.submit(request)
}Always Reschedule
A submitted request runs at most once. To keep refreshing, your handler must submit the next request before it finishes. Reschedule first, then do the work, so a crash mid-work does not stop the cycle.
import BackgroundTasks
func handleRefresh(_ task: BGAppRefreshTask) {
scheduleRefresh() // queue the next run first
// ... then perform this run's work
}Signaling Completion
You must call task.setTaskCompleted(success:) when done. Forgetting it wastes your background budget and can get future tasks deprioritized. Pass whether the work succeeded so the system can adapt scheduling.
import BackgroundTasks
func handleRefresh(_ task: BGAppRefreshTask) {
scheduleRefresh()
Task {
let ok = await fetchLatest()
task.setTaskCompleted(success: ok)
}
}
func fetchLatest() async -> Bool { true }Respecting the Expiration Handler
The system can reclaim time early. Set task.expirationHandler to cancel ongoing work and clean up so you exit gracefully if cut short. Treat it like a deadline alarm.
import BackgroundTasks
func handle(_ task: BGAppRefreshTask) {
let work = Task { await fetchLatest() }
task.expirationHandler = {
work.cancel() // stop before the OS suspends us
}
}
func fetchLatest() async -> Bool { true }Processing Tasks With Requirements
For heavy work, BGProcessingTaskRequest lets you set requiresNetworkConnectivity and requiresExternalPower. The system waits for those conditions, so long tasks run while the device charges overnight on Wi-Fi.
import BackgroundTasks
func scheduleCleanup() {
let req = BGProcessingTaskRequest(
identifier: "com.example.app.cleanup")
req.requiresExternalPower = true
req.requiresNetworkConnectivity = false
try? BGTaskScheduler.shared.submit(req)
}Testing in the Debugger
You will not wait hours for the system to schedule. Pause in the debugger and run an LLDB command to force a registered task to launch immediately, so you can verify the handler end to end.
// In LLDB while paused:
// e -l objc -- (void)[[BGTaskScheduler sharedScheduler]
// _simulateLaunchForTaskWithIdentifier:
// @"com.example.app.refresh"]
let test = "force-launch task via LLDB"
_ = testA Complete Refresh Cycle
Bringing it together: register at launch, submit on background, and in the handler reschedule, guard with an expiration handler, do async work, and report completion.
import BackgroundTasks
func handleRefresh(_ task: BGAppRefreshTask) {
scheduleRefresh()
let work = Task { await fetchLatest() }
task.expirationHandler = { work.cancel() }
Task {
let ok = await work.value
task.setTaskCompleted(success: ok)
}
}
func fetchLatest() async -> Bool { true }Quick Check
Recall the lifecycle of a recurring refresh task.
Recap
You learned background scheduling:
BGAppRefreshTaskfor short refreshes,BGProcessingTaskfor long maintenance with power/network requirements.- Declare identifiers in Info.plist,
registerhandlers at launch, andsubmitrequests with anearliestBeginDate. - Reschedule the next run inside the handler, set an
expirationHandler, and always callsetTaskCompleted. - Force-launch tasks via LLDB to test.
Frequently asked questions
Is the “Background Tasks and Refresh” lesson free?
Yes — the full text of “Background Tasks and Refresh” is free to read here on the web, and the Swift Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.
What will I learn in “Background Tasks and Refresh”?
Schedule background work with BGTaskScheduler. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Swift Academy?
No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Background Tasks and Refresh” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Swift Academy lesson?
Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Registering for Push Notifications
- Handling Notification Payloads
- Background Tasks and Refresh
- Notification Actions and Categories