SwiftUI 윈도우, 씬 및 멀티 윈도우 아키텍처
Source: Dev.to
App vs Scene (The Most Important Distinction)
App
앱이 무엇인지 정의하고, 전역 설정을 소유하며, 씬을 생성합니다.
Scene
앱이 어떻게 표시되는지를 정의하고, 윈도우 수명 주기를 소유하며, 동시에 여러 번 존재할 수 있습니다.
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
RootView()
}
}
}
Rule: 앱은 여러 씬을 가질 수 있으며, 각 씬은 여러 윈도우를 가질 수 있습니다.
What a WindowGroup Really Does
WindowGroup {
ContentView()
}
- iOS: 다중 앱 윈도우 (iPad)
- macOS: 다중 윈도우
- visionOS: 다중 공간 인스턴스
각 윈도우:
- 자신만의 뷰 계층을 가짐
- 자신만의 상태를 가짐
ViewModel을 자동으로 공유하지 않음
The Biggest Multi‑Window Bug
@StateObject var vm = GlobalViewModel()
WindowGroup 안에 @StateObject를 배치하는 것은 다음 이유 때문에 잘못되었습니다:
- 각 윈도우가 새로운 인스턴스를 가짐
- 윈도우 간에 상태가 분기됨
- 네비게이션이 동기화되지 않음
Correct Global State Placement
Global state must live above the scenes:
@main
struct MyApp: App {
@StateObject private var appState = AppState()
var body: some Scene {
WindowGroup {
RootView()
.environmentObject(appState)
}
}
}
Now:
- 모든 윈도우가 동일한 상태를 공유
- 네비게이션이 일관됨
- 데이터가 동기화된 상태 유지
Scene‑Local State vs. App‑Global State
Scene‑local:
- 네비게이션 스택
- 선택
- 포커스
- 스크롤 위치
App‑global:
- 인증
- 사용자 세션
- 캐시
- 기능 플래그
- 딥 링크
절대 혼합하지 마세요.
ScenePhase Is Per‑Scene (Not Global)
@Environment(\.scenePhase) var scenePhase
각 윈도우는 자체적인 단계(phase)를 가지며, 이는 다음을 의미합니다:
- 하나의 윈도우를 백그라운드로 전환해도 앱 전체가 백그라운드가 되는 것은 아님
inactive는 파괴(destroyed)와 동일하지 않음active는 모든 윈도우가 포그라운드에 있는 것과 동일하지 않음
이 정보를 현명하게 활용하세요.
Supporting Multiple Scene Types
SwiftUI allows you to declare several scene roles:
var body: some Scene {
WindowGroup("Main") {
MainView()
}
WindowGroup("Inspector") {
InspectorView()
}
Settings {
SettingsView()
}
}
전형적인 사용 사례:
- 인스펙터 패널
- 설정 윈도우
- 보조 도구
- 디버그 오버레이
Opening New Windows Programmatically
@Environment(\.openWindow) var openWindow
Button("Open Details") {
openWindow(id: "details")
}
열릴 윈도우를 정의합니다:
WindowGroup(id: "details") {
DetailView()
}
이 패턴은 데스크톱급 SwiftUI 앱이 추가 윈도우를 관리하는 방식입니다.
Window‑Scoped Dependency Injection
Each window should receive:
- 자체 네비게이션 상태
- 공유 서비스
- 공유 앱 상태
Example:
WindowGroup {
RootView(
router: Router(),
services: services
)
}
services는 윈도우 간에 공유됩니다router(또는 유사한 네비게이션 객체)는 윈도우당 하나씩 존재합니다
Testing Multi‑Window Behavior
When testing, verify that:
- 여러 윈도우를 올바르게 열고 닫을 수 있음
- 하나의 씬을 백그라운드로 전환해도 다른 씬에 영향을 주지 않음
- 상태 복원이 윈도우당 작동함
- 공유 상태 변경이 예상대로 전파됨
대부분의 SwiftUI 버그는 두 개 이상의 윈도우가 활성화될 때만 나타납니다.
Final Thoughts
SwiftUI scenes are architectural, not boilerplate. Understanding:
- 앱과 씬 구분
- 윈도우 정체성
- 씬‑로컬 vs. 전역 상태
- 멀티‑윈도우 동작
이를 통해 다음과 같은 느낌의 앱을 만들 수 있습니다:
- 네이티브
- 올바른
- 확장 가능한