Background Task는 애플리케이션이 백그라운드로 전환된 후 작업을 완료할 수 있도록 하는 iOS 메커니즘입니다. 시스템은 작업 실행을 위해 제한된 시간(최대 30초)을 할당하며, 이후 애플리케이션은 강제로 일시 중단됩니다. Apple, 2026에 따르면, 만료 핸들러 사용은 백그라운드 작업을 올바르게 완료하기 위한 필수 요구 사항입니다.
핵심 요점
Background Task는 애플리케이션이 백그라운드로 전환된 후 실행 시간을 연장할 수 있도록 하는 프로그래밍 가능한 iOS 메커니즘입니다. 사용자가 앱을 최소화하면 시스템이 UIApplicationDelegate.applicationDidEnterBackground를 호출합니다. 그 순간 중요한 작업(데이터 저장, 요청 전송)이 실행 중인 경우, 애플리케이션은 beginBackgroundTask를 통해 추가 시간을 요청할 수 있습니다.
Background Task를 사용하지 않으면, 애플리케이션은 백그라운드 전환 후 3~5초 이내에 강제로 일시 중단됩니다. 완료되지 않은 모든 작업이 중단됩니다: 데이터가 저장되지 않고, 네트워크 요청이 중단되며, 상태가 손실됩니다. Background Task는 이러한 작업을 올바르게 완료할 수 있도록 최대 30초의 시간을 제공합니다.
beginBackgroundTask는 멀티태스킹을 지원하는 첫 번째 릴리스인 iOS 4.0에서 등장했습니다. iOS 4 이전에는 홈 버튼을 누르면 애플리케이션이 완전히 종료되었습니다. iOS 7에서는 Background Fetch와 URLSession 백그라운드 구성이 도입되었습니다. iOS 13부터 Apple은 새 프로젝트에 BGTaskScheduler를 권장하지만, beginBackgroundTask는 단기 작업에 계속 유용합니다.
beginBackgroundTask는 작업을 등록하고 고유한 UIBackgroundTaskIdentifier를 반환하는 UIApplication 메서드입니다. 시스템이 백그라운드 실행 타이머를 증가시킵니다. 시간이 만료되면 expiration handler가 호출되고, 이후 애플리케이션은 작업을 올바르게 완료하기 위해 endBackgroundTask(identifier:)를 호출해야 합니다.
1단계 — 애플리케이션이 didEnterBackground 알림을 받습니다. 2단계 — beginBackgroundTask(expirationHandler:)가 호출됩니다. 3단계 — 중요한 작업(저장, 네트워크 요청)이 실행됩니다. 4단계 — 완료 시 endBackgroundTask(identifier:)가 호출됩니다. 30초 내에 작업이 완료되지 않으면 시스템이 expiration handler를 호출하고, 애플리케이션은 즉시 작업을 종료해야 합니다.
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
}
backgroundTimeRemaining 속성은 백그라운드 작업이 강제로 종료되기까지 남은 초 수를 반환합니다. 값은 실시간으로 감소합니다. 애플리케이션이 백그라운드에 없으면 DBL_MAX를 반환합니다. 이 속성을 사용하여 동작을 조정하세요: 5초 미만 남았을 때 장기 실행 작업을 중단하고 진행 상황을 저장합니다.
애플리케이션은 여러 Background Tasks를 동시에 등록할 수 있습니다. 각 작업은 고유한 식별자를 받습니다. 총 실행 시간은 누적됩니다 — 3개의 작업이 등록된 경우, 애플리케이션은 최대 90초까지 얻을 수 있습니다. 그러나 리소스가 고갈되거나 배터리 제한을 초과하면 시스템이 애플리케이션을 조기에 종료할 수 있습니다.
Expiration handler는 백그라운드 작업에 할당된 시간이 만료될 때 시스템이 호출하는 코드 블록입니다. expiration handler를 보유하는 것은 Apple의 필수 요구 사항입니다. 이것이 없으면 애플리케이션이 시스템에 의해 강제로 종료되고 데이터가 손실될 수 있습니다.
expiration handler는 애플리케이션 상태를 저장하기 위한 최소한의 작업을 수행해야 합니다: 현재 데이터를 영구 저장소에 저장하고, 해당 식별자로 endBackgroundTask를 호출하며, 식별자를 .invalid로 설정합니다. expiration handler 내에서 새로운 장기 실행 작업을 시작하는 것은 금지됩니다 — 실행 시간이 1~2초로 제한됩니다.
func handleExpiration() {
// 실행 진행 상황 저장 중
saveProgressToUserDefaults()
// 활성 네트워크 요청 취소 중
currentTask?.cancel()
// Background Task 종료 중
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
// Expiration handler로 등록
backgroundTaskID = UIApplication.shared.beginBackgroundTask(
withName: "SaveDocument",
expirationHandler: handleExpiration
)
가장 흔한 실수는 expiration handler 내에서 endBackgroundTask를 호출하지 않는 것입니다. 이 경우 시스템은 작업을 계속 활성 상태로 간주하고, 애플리케이션은 일시 중단 상태로 전환되지 않으며, 배터리가 소모됩니다. 두 번째 실수는 expiration handler 내에서 장기 실행 작업을 시작하는 것입니다. 시스템이 완료되기 전에 애플리케이션을 종료할 수 있으며, 데이터가 손실됩니다.
expiration handler에서 실행 시간은 매우 제한적입니다 — 일반적으로 1초 미만. 따라서 handler 내에서는 다음을 수행할 수 없습니다: 복잡한 계산, 네트워크 요청, CoreData에 대량 데이터 쓰기. 원자적 작업만 가능: UserDefaults에 단일 키 쓰기, 상태 플래그 설정, endBackgroundTask 호출.
앱이 백그라운드로 전환될 때 문서를 저장하기 위한 완전한 Background Task 구현을 살펴보겠습니다. 예제에는 작업 등록, 남은 시간 확인을 통한 작업 실행, endBackgroundTask를 통한 올바른 완료가 포함됩니다.
백그라운드로 전환될 때, 애플리케이션은 큰 문서의 저장을 시작합니다. Background Task는 작업에 최대 30초를 제공합니다. 시간이 만료되면 expiration handler가 중간 결과를 저장합니다. 저장이 완료된 후, 리소스를 해제하기 위해 endBackgroundTask가 호출됩니다.
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
}
}
백그라운드에서의 네트워크 요청은 특별한 주의가 필요합니다 — expiration handler가 응답을 받기 전에 요청을 중단할 수 있습니다. dataTask와 함께 URLSession을 사용하고 전송 전에 backgroundTimeRemaining을 확인하세요. 5초 미만 남은 경우, 다음 앱 실행까지 전송을 연기하세요.
func sendCriticalData(data: Data) {
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
// 재전송을 위한 데이터 저장 중
saveForRetry(data)
self.endBackgroundTask()
}
let task = URLSession.shared.dataTask(with: request) { _, _, error in
if error != nil {
saveForRetry(data)
}
self.endBackgroundTask()
}
task.resume()
}
장기 실행 작업의 경우 UIApplication.shared.backgroundTimeRemaining을 모니터링하세요. 값이 임계값(10초) 아래로 떨어지면 현재 작업을 중단하고 중간 결과 저장을 시작하세요. 이렇게 하면 expiration handler가 강제로 호출되기 전에 올바르게 완료할 수 있습니다.
Background Task는 강력한 메커니즘이지만, 부적절하게 사용하면 배터리 및 성능 문제가 발생합니다. Apple의 권장 사항과 커뮤니티에서 검증된 방법을 따르면 일반적인 실수를 피하고 안정적인 애플리케이션 운영을 보장할 수 있습니다.
Background Task를 가능한 한 빨리 완료하세요. 백그라운드 실행의 1초마다 배터리를 소모합니다. 최적 시간 — 5초 미만. 작업 시간이 더 오래 걸리면 BGTaskScheduler 또는 Background Modes 사용을 고려하세요. 실제 필요 없이 beginBackgroundTask 호출로 인위적으로 작업을 연장하지 마세요.
UIBackgroundTaskIdentifier를 클래스 또는 구조체 속성으로 저장하세요. 전역 변수로 전달하지 마세요 — 여러 작업에서 충돌이 발생합니다. 이중 완료를 방지하기 위해 endBackgroundTask 호출 후 식별자를 .invalid로 설정하세요.
Xcode 시뮬레이터에서 홈 버튼(Command + Shift + H)을 통해 앱을 백그라운드로 전환하세요. Debug — Simulate Background Fetch를 사용하여 백그라운드 실행을 테스트하세요. 시간 만료를 시뮬레이션하려면 환경 변수 BACKGROUND_TASK_SIMULATE_EXPIRATION = YES를 설정하세요 — expiration handler가 5초 이내에 호출됩니다.
// 작업 시작 전 남은 시간 확인
let remaining = UIApplication.shared.backgroundTimeRemaining
guard remaining > 10.0 else {
// 시간 부족 — 작업 연기
scheduleForNextLaunch()
return
}
// 시간 제어로 작업 실행
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
saveProgress()
self.endBackgroundTask()
}
expiration handler는 self를 캡처합니다 — backgroundTaskID가 동일한 객체의 속성으로 저장된 경우 retain cycle이 발생할 수 있습니다. 클로저에서 [weak self]를 사용하거나 식별자를 별도로 저장하세요. Retain cycle은 메모리 누수를 일으켜 애플리케이션이 종료될 때까지 객체가 해제되지 않습니다.
iOS 13 출시와 함께 Apple은 BGTaskScheduler를 도입했습니다 — 기존 Background Task API의 현대적인 대체품입니다. 두 메커니즘 모두 유사한 작업을 해결하지만, BGTaskScheduler는 더 많은 제어와 유연성을 제공합니다. 차이점을 이해하면 특정 시나리오에 적합한 도구를 선택하는 데 도움이 됩니다.
| 특성 | Background Task | BGTaskScheduler |
|---|---|---|
| iOS 버전 | 4.0+ | 13.0+ |
| 최대 시간 | 30초 | 30초 / 10분 (processing) |
| 시작 | didEnterBackground | 스케줄링 + 시스템 |
| 실행 보장 | 백그라운드 전환 시에만 | 시스템이 편리한 모든 시간 |
| Expiration handler | 예, 필수 | 예, task.expirationHandler를 통해 |
| 인터넷 | 시작 시 필요 | requiresNetworkConnectivity를 통해 사용 가능 |
| 충전 | 필요 없음 | processing에서 선택 사항 |
beginBackgroundTask는 백그라운드 전환 시 즉시 실행해야 하는 단기 작업에 적합합니다: 상태 저장, 네트워크 요청 완료, 데이터 캐싱. API가 간단하고 Info.plist 구성이나 식별자 등록이 필요하지 않습니다. 10초 미만이 소요되는 작업에 이상적입니다.
BGTaskScheduler는 편리한 시간에 실행할 수 있는 작업에 적합합니다: 주기적 동기화, 캐시 정리, 위젯 업데이트. 시스템 자체가 사용자 행동과 배터리 상태를 고려하여 최적의 시간을 선택합니다. 장기 실행 작업(최대 10분)에는 BGProcessingTask를 사용하세요.
두 API를 동일한 애플리케이션에서 사용할 수 있습니다. Background Task — 백그라운드 전환 시 즉시 작업(초안 저장)에 사용합니다. BGTaskScheduler — 예약된 업데이트(6시간마다 동기화)에 사용합니다. 책임 분리를 통해 데이터의 올바른 보존과 에너지 효율적인 백그라운드 유지보수를 보장합니다.
자주 묻는 질문
네, beginBackgroundTask는 애플리케이션 실행 중 언제든지 호출할 수 있습니다. 그러나 시스템 시간 할당은 백그라운드로 전환된 후에만 시작됩니다. 애플리케이션이 포그라운드에 있는 경우 beginBackgroundTask를 호출해도 효과가 없습니다 — backgroundTimeRemaining이 DBL_MAX를 반환하고, 작업은 백그라운드로 전환될 때 활성화됩니다.
endBackgroundTask가 호출되지 않으면 시스템은 애플리케이션을 백그라운드에서 활성 상태로 계속 간주합니다. 30초 후에 expiration handler가 호출되지만, 여기에도 endBackgroundTask가 없으면 애플리케이션이 메모리에 남아 배터리를 소모합니다. iOS 13+에서는 시스템이 3분 후에 해당 애플리케이션을 강제 종료합니다.
표준 시간은 30초입니다. Background Modes: 오디오(재생), 위치(GPS), 블루투스(BLE)를 통해서만 연장할 수 있습니다. 또는 BGProcessingTask(iOS 13+)를 통해 충전 및 Wi-Fi 환경에서 최대 10분까지 가능합니다. beginBackgroundTask 자체는 제한을 늘리는 방법을 제공하지 않습니다.
네, iPadOS는 iOS와 동일한 제한 사항으로 beginBackgroundTask를 완전히 지원합니다. Stage Manager가 있는 iPad에서는 애플리케이션이 메모리에 더 오래 머무를 수 있습니다 — 더 큰 RAM으로 인해 시스템이 애플리케이션을 덜 자주 일시 중단합니다. 그러나 백그라운드 작업의 30초 제한은 유지됩니다.
기기를 Xcode에 연결하고, 애플리케이션을 실행한 후 최소화하면 콘솔에 시스템 로그가 표시됩니다. sysdiagnose를 사용하여 자세한 로그를 수집하세요: 기기에서 sysdiagnose를 강제 트리거합니다(볼륨 업 + 볼륨 다운 + 전원). Xcode Debug Navigator에서 백그라운드 작업 활동을 모니터링하세요.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.