일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- App Store Connect
- 단일 책임원칙
- MKMapItem
- Startign Assignments
- font book
- UIAlertAction
- WeatherManager
- 영문 개인정보처리방침
- weak var
- UICollectionViewFlowLayout
- SwiftUI Boolean 값
- 서체관리자
- CoreLocation
- Required Reason API
- weatherKit
- MKMapViewDelegate
- 러닝타이머
- 클로저의 캡슐화
- CLLocationManagerDelegate
- Protocol
- swift
- xcode로 날씨앱 만들기
- AnyObject
- 한국어 개인정보처리방침
- Xcode
- 러닝기록앱
- RunningTimer
- addannotation
- dispatchsource
- Timer
- Today
- Total
VesselWheel
Background Tasks 본문
https://www.youtube.com/watch?v=Lb7OShyNSdM
https://developer.apple.com/documentation/backgroundtasks/
https://velog.io/@yoosa3004/iOS-Background-Mode-Background-Task
이해를 돕기 위해 유튜브에서 관련 영상을 참고하고 공식문서와 블로그를 참고하였다.
실제 구현 관련 공식문서가 있어 한번 더 참고하였다.
import UIKit
import CoreData
import BackgroundTasks
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
let taskID = "RunningTimer" // Info.plist에 등록한 키 값을 전역 상수로 선언
var myTimer: MyTimer?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Register handler for task, Task는 launch Handler를 갖는 BGTaskScheduler 객체로 고유한 식별자를 갖는다.
// 모든 Task는 app launch sequence가 끝나기 전에 BGTaskScheduler에 등록해야하기 때문에, launch가 끝나는 시점인 didFinishLaunchingWithOptions에서 호출하면 된다.
registerBackgroundTasks()
return true
}
// 앱의 launch sequence가 끝나기 전에 Background Task를 Scheduler에 "등록"해야 합니다.
// Info.plist에 등록한 키 값으로 등록해야 합니다.
private func registerBackgroundTasks() {
print("Background Task 등록!")
// 1. Refresh Task 등록
BGTaskScheduler.shared.register(forTaskWithIdentifier: taskID, using: nil) { task in
// Handle the task in your app
self.handleAppRefresh(task: task as! BGAppRefreshTask)
}
}
// 2. 실제로 수행할 Background 동작 구현
func handleAppRefresh(task: BGAppRefreshTask) {
// Schedule a new refresh task
scheduleAppRefresh()
// Initialize MyTimer and start it
myTimer = MyTimer(time: 0, distance: 0.0, pace: 0.0, updateUI: {
// Post a notification with the timer's state
NotificationCenter.default.post(name: Notification.Name("TimerUpdated"), object: self.myTimer)
})
myTimer?.startTimer()
// Get the current status of the timer
let status = self.myTimer?.getCurrentStatus() ?? "No Status"
print(status)
// Provide an expiration handler for the background task
// that cancels the operation
task.expirationHandler = {
self.myTimer?.stopTimer()
task.setTaskCompleted(success: false)
}
}
func scheduleAppRefresh() {
let request = BGProcessingTaskRequest(identifier: taskID) //BGProcessingTaskRequest, BGAppRefreshTaskRequest
request.requiresExternalPower = true // 배터리를 사용할 것인지 여부
request.requiresNetworkConnectivity = true // 네트워크를 사용할 것인지 여부
request.earliestBeginDate = Date(timeIntervalSinceNow: 1 * 60) // Fetch no earlier than 1 minutes from now
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Could not schedule app refresh: \(error)")
}
}
요약 해석
백그라운드 작업은 앱이 포그라운드에서 실행되지 않아도 실행되는 작업을 말합니다. 이 코드에서는 백그라운드 작업을 이용해 러닝 타이머를 구현하고 있습니다.
- application(_:didFinishLaunchingWithOptions:) 함수에서 백그라운드 작업을 등록합니다. 이 함수는 앱이 처음 시작될 때 호출됩니다.
- registerBackgroundTasks() 함수에서는 백그라운드 작업을 등록합니다. BGTaskScheduler.shared.register를 사용해 작업을 등록하고, 해당 작업이 실행될 때 호출될 클로저를 정의합니다. 여기서는 handleAppRefresh(task:) 함수를 호출하도록 되어 있습니다.
- handleAppRefresh(task:) 함수에서는 실제로 백그라운드 작업을 처리합니다. 먼저, 다음 백그라운드 작업을 예약하고, MyTimer 인스턴스를 생성하고 시작합니다. 그리고 MyTimer의 상태를 콘솔에 출력합니다. 마지막으로, 작업이 시스템에 의해 중지되어야 할 때를 대비해 만료 핸들러를 제공합니다. 만료 핸들러에서는 타이머를 중지하고 작업을 완료하지 않았음을 시스템에 알립니다.
- scheduleAppRefresh() 함수에서는 다음 백그라운드 작업을 예약합니다. BGAppRefreshTaskRequest를 생성하고, BGTaskScheduler.shared.submit을 사용해 작업을 예약합니다.
이 코드를 통해 앱이 백그라운드에서도 활성 상태를 유지하면서 러닝 타이머 기능을 계속 사용할 수 있게 됩니다.
-> Background Tasks의 유형 : BGAppRefreshTaskRequest, BGProcessingTaskRequest
`BGAppRefreshTaskRequest`와 `BGProcessingTaskRequest`는 iOS의 BackgroundTasks 프레임워크에서 제공하는 두 가지 주요 백그라운드 작업 유형입니다. 각각 다음과 같은 상황에서 사용됩니다:
1. `BGAppRefreshTaskRequest`: 앱의 콘텐츠를 최신 상태로 유지하거나 앱이 백그라운드에 있을 때 작은 작업을 수행하는 데 사용됩니다. 예를 들어, 앱이 백그라운드에 있을 때 새로운 데이터를 미리 가져오거나, 알림을 스케줄링하는 등의 작업을 수행할 수 있습니다. 이 작업은 시스템에 큰 부담을 주지 않으며, 사용자의 배터리 수명에 큰 영향을 미치지 않아야 합니다.
2. `BGProcessingTaskRequest`: 더 많은 자원을 필요로 하는 작업에 사용됩니다. 이 작업은 사용자의 배터리를 많이 사용하거나, 네트워크 연결이 필요하거나, 외부 전원이 연결된 상태에서만 수행될 수 있습니다. 이 작업은 대개 사용자가 앱을 사용하지 않는 시간에 큰 데이터를 처리하거나 다운로드하는 등의 작업을 수행하는 데 사용됩니다.
두 작업 유형 모두 백그라운드에서 실행되지만, 각각의 작업 유형은 서로 다른 요구 사항과 제한 사항을 가지고 있습니다. 따라서 앱의 요구 사항에 따라 적절한 작업 유형을 선택해야 합니다.
-> 외부 전원이 연결된 상태에서 달리기는 하는 것이 아니고, 타이머를 UI로 알림하는 것이므로 BGAppRefreshTaskRequest로 진행
=> 하지만 러닝 타이머는 지속적인 타이머를 운용할 필요는 없고 Scene이 포그라운드에서 백그라운드로, 백그라운드에서 포그라운드로 넘어갈 때 러닝기록 프로퍼티를 저장하고, 호출하면 배터리 사용없이 Scene의 변경마다 UI나 Task를 할당 할 수 있다고 한다.
따라서, 아래의 글을 참고하여 구현해보고자 한다.
'Xcode Study' 카테고리의 다른 글
SceneDeleagte(for 러닝기록 타이머) (0) | 2024.02.29 |
---|---|
러닝기록 타이머 만들기(3/3)(with dispatchsource ) (0) | 2024.02.27 |
러닝기록 타이머 만들기(2/3)(with thread, RunLoop) (0) | 2024.02.27 |
TIL의 중요성(feat. 능소부능대(能小復能大)) (0) | 2024.02.27 |
러닝기록 타이머 만들기(1/3)(with thread, RunLoop) (0) | 2024.02.26 |