iOS/Swift

Managing your app’s life cycle

태애니 2025. 4. 30. 18:32
728x90

Foreground 에 있는 앱은 CPU를 포함한 시스템 리소스에서 우선권을 가진다.

Background 에 있을 경우 가능한 작업을 적게 해야하고, 이상적으로는 아무것도 안하는게 좋다.

 

앱의 상태가 바뀔 때마다 적절한 delegate 를 가져와야하는데

iOS13 이후로는 UISceneDelegate 객체를 이용한다

 

 

UIScene 단위에 대해서 알아보도록 해야겠다.

 

앱의 하나의 Scene = 하나의 UI인스턴스에 대한 라이프사이클과 상태 변화를 관리한다.

 

 

 

// SceneDelegate.swift
class SceneDelegate: UIResponder, UISceneDelegate {
    
    var window: UIWindow?

    func scene(_ scene: UIScene,
               willConnectTo session: UISceneSession,
               options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = scene as? UIWindowScene else { return }
        
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = YourRootViewController()
        self.window = window
        window.makeKeyAndVisible()
    }
    
    func sceneDidBecomeActive(_ scene: UIScene) {
        // Scene이 Active 상태로 들어갈 때
    }

    func sceneWillResignActive(_ scene: UIScene) {
        // Scene이 Inactive 상태로 가기 직전
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        // Scene이 백그라운드로 갈 때
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        // Scene이 포그라운드로 돌아올 때
    }

    func sceneDidDisconnect(_ scene: UIScene) {
        // Scene이 시스템에 의해 끊길 때 (메모리 회수 등)
    }
}

 

 

 

import SwiftUI

@main
struct MyApp: App {
    
    @Environment(\.scenePhase) private var scenePhase

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: scenePhase) { newPhase in
            switch newPhase {
            case .active:
                print("앱이 Active 상태입니다.")
            case .inactive:
                print("앱이 Inactive 상태입니다.")
            case .background:
                print("앱이 Background 상태입니다.")
            @unknown default:
                print("알 수 없는 상태입니다.")
            }
        }
    }
}

 

 

 

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup { // 여기가 Scene 단위
            ContentView()  // 여기 ContentView는 View단위
        }
    }
}

 

 

 

iPadOS나 macOS에서는 하나의 앱에서 여러 개의 Scene을 띄울 수 있다.

(예를 들면, 메일 앱에서 새 메일을 작성할 때 새 창이 뜨는 것 = 새로운 Scene)

 

SwiftUI에서는 그것도 자연스럽게 WindowGroup 여러 개로 관리할 수 있다.

 

 

 

 

Scene을 여러 개 만들 때 주의할 점

  1. 상태 관리: 여러 Scene 간에 데이터를 공유하려면 @EnvironmentObject나 전역 상태 관리 방식이 필요.
  2. 메모리 관리: Scene의 리소스를 적절히 해제하고 관리.
  3. UI 동기화: 하나의 Scene에서 데이터 변경 시 다른 Scene의 UI도 자동으로 갱신되도록 해야 함.
  4. 라이프사이클 관리: 각 Scene의 라이프사이클을 독립적으로 관리하고, Scene이 활성화/비활성화될 때 적절한 작업을 처리 필요.
  5. 기기 크기와 레이아웃: 각 Scene에 대해 다양한 화면 크기와 레이아웃을 지원해야함.
  6. 백그라운드 작업: Scene이 백그라운드로 이동할 때, 작업을 처리하고 리소스를 절약하는 방법을 고려해야함.

 

 

 

onAppear, onDisappear 등은 View 단위의 동작 이벤트라는 점

 

 

이벤트설명사용 예시 

onAppear 뷰가 화면에 나타날 때 호출됩니다. Text("Hello, World!") .onAppear { print("뷰가 화면에 나타났습니다.") }
onDisappear 뷰가 화면에서 사라질 때 호출됩니다. Text("Goodbye!") .onDisappear { print("뷰가 화면에서 사라졌습니다.") }
onChange(of:perform:) 특정 값이 변경될 때 호출됩니다. @State private var count = 0 Text("Count: \(count)").onChange(of: count) { print("Count 값이 변경되었습니다.") }
task 뷰가 처음 나타날 때 비동기 작업을 시작합니다. Text("Fetching data...").task { await fetchData() }
onTapGesture 사용자가 터치를 했을 때 호출됩니다. Text("Tap me").onTapGesture { print("Tapped!") }
onLongPressGesture 사용자가 롱프레스(길게 누르기)를 했을 때 호출됩니다. Text("Long press me").onLongPressGesture { print("Long pressed!") }
simultaneousGesture 여러 제스처가 동시에 발생할 때 모두 처리합니다. Text("Simultaneous gesture").simultaneousGesture(TapGesture().onEnded { print("Tapped!") })
focusable 텍스트 필드나 버튼 등 뷰가 포커스를 받을 때 호출됩니다. TextField("Enter text", text: $text).focusable().onChange(of: focused) { _ in print("포커스를 받았습니다.") }
onPreferenceChange 부모 뷰와 자식 뷰 간의 데이터 변경 사항을 처리합니다. Text("Value: \(value)").onPreferenceChange(MyPreferenceKey.self) { value in self.value = value }
animation 상태 변경에 애니메이션 효과를 적용할 때 사용됩니다. withAnimation { isVisible.toggle() } (애니메이션 효과와 상태 변경)
728x90