Motivation
- 앱 개발 중 네트워크 상태 확인이나 인증 토큰 갱신 같은 로직을 포그라운드 복귀 시점에 실행해야하는 경우
- UIKit에서는
SceneDelegate의sceneWillEnterForeground,sceneDidBecomeActive,sceneDidEnterBackground등 구현 필요 - SwiftUI에서는
\.scenePhase라는 Environment 값으로 간단하게 처리할 수 있음
- UIKit에서는
Overview
scenePhase란?
SwiftUI가 제공하는 Environment 값으로, 현재 Scene의 상태를 나타낸다.
.active앱이 포그라운드에 있고 사용자와 상호작용 가능.inactive앱이 포그라운드에 있지만 상호작용 불가 (예: 멀티태스킹 전환 중).background앱이 백그라운드로 이동한 상태
사용
@Environment(\.scenePhase) var scenePhase
var body: some View {
ContentView()
.onChange(of: scenePhase) { oldPhase, newPhase in
switch newPhase {
case .active:
print("앱 활성화")
case .inactive:
print("앱 비활성화")
case .background:
print("백그라운드로 이동")
@unknown default:
break
}
}
}
참고
onChange(of:)클로저에서oldPhase,newPhase두 파라미터를 받는 형태는 iOS 17+ 문법이다. iOS 16 이하를 지원해야 한다면 단일 파라미터 형태({ phase in ... })를 사용해야 한다.
.onAppear vs scenePhase pros and cons
onAppear
Pros
- 특정 뷰가 화면에 나타날 때만 실행되므로 뷰 단위 제어에 적합
- 탭 전환이나 네비게이션 push/pop 시에도 호출
- 뷰마다 서로 다른 로직을 적용할 수 있다.
Cons
- 백그라운드 → 포그라운드 복귀 시에는 호출되지 않음.
- 같은 뷰가 여러 번 나타나면 중복 호출
- 앱 전체 상태 관리 용도로는 부적합
scenePhase
Pros
- 앱 전체 생명주기 변화를 한 곳에서 관리할 수 있음
- 앱 최초 실행과 포그라운드 복귀를 동일한 코드로 처리 가능
- 상태 전환당 한 번만 호출되므로 중복 호출 걱정 없음
Cons
- 뷰 단위 세밀한 제어 불가
- 탭 전환 같은 앱 내부 이동은 감지 못함
- 루트 뷰에서만 사용하는 게 일반적
사용 예시
- 상황추천네트워크 연결/인증 상태 확인 →
scenePhase - 특정 화면 진입 시 데이터 로드 →
onAppear/task - 앱 전체 상태 동기화 →
scenePhase - 화면별 애널리틱스 트래킹 →
onAppear
요약
- 앱 레벨 →
scenePhase - 뷰 레벨 →
onAppear
task vs onAppear
- Apple은 iOS 15부터
taskmodifier를 도입- 비동기 작업이 필요한 경우
onAppear안에서Task { ... }를 직접 생성하는 것보다task를 사용하는 편이 낫다 task의 가장 큰 장점인 뷰의 생명주기와 작업의 생명주기의 자동 연동- 뷰가 사라지면 진행 중인 비동기 작업이 자동으로 취소되므로, 화면을 빠르게 이탈했을 때 불필요한 네트워크 요청이 계속되는 문제 방지
- 비동기 작업이 필요한 경우
// task 사용 (iOS 15+)
struct ContentView: View {
var body: some View {
List(items) { item in
Text(item.name)
}
.task {
await loadData()
}
}
}
Apple에서 권장하는 방식?
위에서 “권장"이라고 표현한 부분들은, Apple이 공식 문서에서 “반드시 이렇게 해야 한다"고 명시한 것은 아님
scenePhase문서는 “You can observe the current scene phase in your app’s App instance.” 라고 사용 방법을 설명할 뿐.task문서도 “Use this modifier to perform an asynchronous task with a lifetime that matches the lifetime of the modified view.” 라고 적합성을 설명.- WWDC 세션들 역시 “이렇게 쓸 수 있다"는 예시를 보여주는 것이지 규범적 표현은 아님.
공식 문서와 WWDC 예제 코드에서 사용하는 패턴이자, 커뮤니티에서 통용되는 베스트 프랙티스로 이해
GitHub Comments