Skip to content
All essays
iOSMarch 27, 202512 min

Swift Background Tasks: Schedule and Execute

Implement background tasks in iOS apps. Background fetch, processing, and scheduling.

Ü
Ümit Uz
Mobile & Full Stack Developer

Background tasks allow your app to perform work when it's not actively running. Learn to schedule and execute background tasks efficiently.

Background Tasks Setup

Enable Background Modes

  1. 1Go to Project Settings > Signing & Capabilities
  2. 2Add "Background Modes" capability
  3. 3Enable required modes:

- Background fetch - Background processing - Remote notifications

Background Fetch

Schedule Background Fetch

swift
import BackgroundTasks

class BackgroundFetchManager {
    private let backgroundTaskIdentifier = "com.yourapp.backgroundFetch"

    func scheduleBackgroundFetch() {
        let request = BGAppRefreshTaskRequest(identifier: backgroundTaskIdentifier)

        do {
            try BGTaskScheduler.shared.submit(request)
            print("Background fetch scheduled")
        } catch {
            print("Failed to schedule background fetch: \(error)")
        }
    }
}

Handle Background Task

swift
class AppDelegate: NSObject, UIApplicationDelegate, BGTaskSchedulerDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
    ) -> Bool {
        BGTaskScheduler.shared.register(
            forTaskWithIdentifier: "com.yourapp.backgroundFetch",
            using: nil
        ) { task in
            self.handleBackgroundFetch(task as! BGAppRefreshTask)
        }

        return true
    }

    private func handleBackgroundFetch(_ task: BGAppRefreshTask) {
        // Schedule next background fetch
        let nextFetch = BGAppRefreshTaskRequest(identifier: "com.yourapp.backgroundFetch")
        nextFetch.earliestBeginDate = Date(timeIntervalSinceNow: 3600) // 1 hour

        try? BGTaskScheduler.shared.submit(nextFetch)

        // Perform background work
        Task {
            await self.performBackgroundWork()

            task.setTaskCompleted(success: true)
        }

        // Expiration handler
        task.expirationHandler = {
            task.setTaskCompleted(success: false)
        }
    }

    private func performBackgroundWork() async {
        // Fetch data, update content, etc.
        print("Performing background work")
    }
}

Background Processing

Schedule Background Processing

swift
class BackgroundProcessingManager {
    private let processingTaskIdentifier = "com.yourapp.processing"

    func scheduleBackgroundProcessing() {
        let request = BGProcessingTaskRequest(identifier: processingTaskIdentifier)
        request.requiresNetworkConnectivity = true
        request.requiresExternalPower = false

        do {
            try BGTaskScheduler.shared.submit(request)
            print("Background processing scheduled")
        } catch {
            print("Failed to schedule processing: \(error)")
        }
    }
}

Handle Processing Task

swift
extension AppDelegate {
    func registerBackgroundProcessing() {
        BGTaskScheduler.shared.register(
            forTaskWithIdentifier: "com.yourapp.processing",
            using: nil
        ) { task in
            self.handleBackgroundProcessing(task as! BGProcessingTask)
        }
    }

    private func handleBackgroundProcessing(_ task: BGProcessingTask) {
        // Schedule next processing
        scheduleNextProcessing()

        // Perform heavy processing
        Task {
            await performHeavyProcessing()

            task.setTaskCompleted(success: true)
        }

        task.expirationHandler = {
            task.setTaskCompleted(success: false)
        }
    }

    private func scheduleNextProcessing() {
        let request = BGProcessingTaskRequest(identifier: "com.yourapp.processing")
        request.requiresNetworkConnectivity = true

        try? BGTaskScheduler.shared.submit(request)
    }

    private func performHeavyProcessing() async {
        // Process data, sync with server, etc.
    }
}

URLSession Background Tasks

Background Downloads

swift
class BackgroundDownloadManager: NSObject, URLSessionDelegate {
    private var session: URLSession!

    override init() {
        super.init()

        let configuration = URLSessionConfiguration.background(withIdentifier: "com.yourapp.backgroundDownload")
        configuration.sessionSendsLaunchEvents = true
        configuration.isDiscretionary = false

        session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
    }

    func startBackgroundDownload(url: URL) {
        let task = session.downloadTask(with: url)
        task.resume()
    }
}

extension BackgroundDownloadManager {
    func urlSession(
        _ session: URLSession,
        downloadTask: URLSessionDownloadTask,
        didFinishDownloadingTo location: URL
    ) {
        // Handle downloaded file
        print("Download completed to: \(location)")
    }

    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        if let error = error {
            print("Download failed: \(error)")
        }
    }
}

Background App Refresh

Manual Refresh Trigger

swift
class AppRefreshManager {
    func triggerAppRefresh() {
        let refreshTask = BGAppRefreshTaskRequest(identifier: "com.yourapp.refresh")
        refreshTask.earliestBeginDate = Date(timeIntervalSinceNow: 60) // 1 minute

        do {
            try BGTaskScheduler.shared.submit(refreshTask)
        } catch {
            print("Failed to trigger refresh: \(error)")
        }
    }
}

Background URL Session Configuration

Configure for Background Uploads

swift
class BackgroundUploadManager {
    private var session: URLSession!

    init() {
        let config = URLSessionConfiguration.background(withIdentifier: "com.yourapp.backgroundUpload")
        config.httpMaximumConnectionsPerHost = 1
        config.isDiscretionary = false

        session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
    }

    func uploadFile(fileURL: URL, to endpoint: URL) {
        var request = URLRequest(url: endpoint)
        request.httpMethod = "POST"

        let task = session.uploadTask(with: request, fromFile: fileURL)
        task.resume()
    }
}

extension BackgroundUploadManager: URLSessionDelegate {
    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        if let error = error {
            print("Upload failed: \(error)")
        } else {
            print("Upload completed")
        }
    }
}

Background Task Scheduler

Check Task Status

swift
extension BackgroundTasksManager {
    func getTaskStatus(identifier: String) async -> BGTaskScheduler.Status? {
        return await BGTaskScheduler.shared.status(forTaskWithIdentifier: identifier)
    }

    func cancelAllTasks() {
        BGTaskScheduler.shared.cancelAllTaskRequests()
    }
}

Best Practices

  1. 1Battery: Minimize battery usage
  2. 2Network: Check network availability
  3. 3Duration: Keep tasks short
  4. 4Expiration: Handle task expiration
  5. 5Scheduling: Schedule appropriate intervals
  6. 6Testing: Test background modes thoroughly
  7. 7Fallback: Provide fallback for failures
  8. 8User Experience: Inform users about background activity

Background tasks enable your app to stay up-to-date!

Related essays

Next essay
SwiftUI Forms Complete Guide: Input and Validation