Moon Work

iOS 13 이상에서의 App Life Cycle(AppDelegate, SceneDelegate) 본문

iOS

iOS 13 이상에서의 App Life Cycle(AppDelegate, SceneDelegate)

moonkey 2025. 3. 12. 22:42

 

CS 스터디에 참여하면서 다시 기본기를 다지고 있습니다. 재미있는 내용이 많은데, SceneDelegate를 통해 어떻게 로그가 찍히는지 확인해보겠습니다. 

App Life Cycle

사실 앱의 라이프 사이클과 관련해서는 애플에서도 너무 정리를 잘 해두었고, 좋은 리소스가 많습니다. 라이프 사이클에 대한 배경은 아래 참고로 남겨두겠습니다. 

https://developer.apple.com/documentation/uikit/managing-your-app-s-life-cycle

 

Managing your app’s life cycle | Apple Developer Documentation

Respond to system notifications when your app is in the foreground or background, and handle other significant system-related events.

developer.apple.com

https://blog.naver.com/doctor-kick/222423840595

 

[iOS] 앱의 생명주기(LifeCycle) AppDelegate

생명주기 (Life Cycle)이란? 생명주기라는 것은 앱의 최초 실행부터 앱이 완전이 종료되기까지 앱이 가지...

blog.naver.com

https://medium.com/hcleedev/swift-swiftui-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-appdelegate-scenedelegate-%EB%A7%8C%EB%93%A4%EA%B8%B0-4fa2d85191e

 

Swift: SwiftUI 프로젝트에 AppDelegate, SceneDelegate 만들기

AppDelegate와 SceneDelegate 만드는 법, 그리고 그 두 파일 없이도 대응하는 법을 알아보자

medium.com

 

그래서 언제 어떤 함수가 호출되는걸까?

AppDelegate, SceneDelegate.. 함수명도 길어서 헷갈리네요. 이럴 때는 프로젝트에서 직접 확인해보는 것을 선호합니다. 

저는 아래 AppDelegate를 만들고 SwiftUI에서 사용하기 위해

`@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate`

를 앱 최상단에 선언하여 앱의 상태관리에 대해 이전하였습니다. 

import SwiftUI

class AppDelegate: NSObject, UIApplicationDelegate {
    func applicationWillEnterForeground(_ application: UIApplication) {
        print("""
            ---
            Background -> InActive
            앱이 Background에서 InActive로 전활될 때 호출됩니다.
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
    }

    func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        print("""
            ---
            InActive
            main storyboard, nib 파일이 로드된 이후 호출되며 초기화 및 실행 준비를 합니다. 
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
        return true
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        print("""
            ---
            InActive -> Active
            앱을 실행시키기 위한 모든 설정을 완료하고 화면을 보여주기 직전에 호출됩니다.
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
        return true
    }
    func applicationDidBecomeActive(_ application: UIApplication) {
        print("""
            ---
            Active
            Active 상태가 된 직후 호출됩니다. 
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
    }
    func applicationWillResignActive(_ application: UIApplication) {
        print("""
            ---
            Active -> InActive
            Active 상태에서 InActive 상태가 된 직후 호출됩니다.  
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
    }
    func applicationDidEnterBackground(_ application: UIApplication) {
        print("""
            ---
            Background
            앱이 Background 상태가 되었을 때 호출됩니다.   
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
    }

    func applicationWillTerminate(_ application: UIApplication) {
        print("""
            ---
            Background -> Not Running
            앱이 종료될 때 호출됩니다.    
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
    }

}


@main
struct TestProjectApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

 

로그가 찍히지 않습니다? 

제 기대는 앱을 작동하면 촤라라락 로그가 찍힐 줄 알았는데

`application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool`

`func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool`

에 대한 로그만 찍힌 것을 확인했습니다. 이건 너무 이상했지만, iOS 13부터 적용된 SceneDelegate의 존재를 알고 있었기 때문에 SceneDelegate를 아래와 같이 적용해서 다시 로그를 찍어보았습니다. 

import SwiftUI

class AppDelegate: NSObject, UIApplicationDelegate {
    func applicationWillEnterForeground(_ application: UIApplication) {
        print("""
            ---
            Background -> InActive
            앱이 Background에서 InActive로 전활될 때 호출됩니다.
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
    }

    func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        print("""
            ---
            InActive
            main storyboard, nib 파일이 로드된 이후 호출되며 초기화 및 실행 준비를 합니다. 
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
        return true
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        print("""
            ---
            InActive -> Active
            앱을 실행시키기 위한 모든 설정을 완료하고 화면을 보여주기 직전에 호출됩니다.
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
        return true
    }
    func applicationDidBecomeActive(_ application: UIApplication) {
        print("""
            ---
            Active
            Active 상태가 된 직후 호출됩니다. 
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
    }
    func applicationWillResignActive(_ application: UIApplication) {
        print("""
            ---
            Active -> InActive
            Active 상태에서 InActive 상태가 된 직후 호출됩니다.  
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
    }
    func applicationDidEnterBackground(_ application: UIApplication) {
        print("""
            ---
            Background
            앱이 Background 상태가 되었을 때 호출됩니다.   
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
    }

    func applicationWillTerminate(_ application: UIApplication) {
        print("""
            ---
            Background -> Not Running
            앱이 종료될 때 호출됩니다.    
            호출된 함수: \(#function)
            호출한 객체 \(String(describing: type(of: self)))
            """
        )
    }
    func application(
        _ application: UIApplication,
        configurationForConnecting connectingSceneSession: UISceneSession,
        options: UIScene.ConnectionOptions
      ) -> UISceneConfiguration {
        let sceneConfig = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role)
        sceneConfig.delegateClass = MySceneDelegate.self
        return sceneConfig
      }
}

class MySceneDelegate: NSObject, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let _ = (scene as? UIWindowScene) else { return }
    }

    func sceneDidDisconnect(_ scene: UIScene) {
        print(#function)
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        print(#function)
    }

    func sceneWillResignActive(_ scene: UIScene) {
        print(#function)
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        print(#function)
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        print(#function)
    }
}


@main
struct TestProjectApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

 

로그를 보겠소

SceneDelegate에서 호출한 로그들이 잘 찍히는 것을 확인할 수 있습니다. SceneDelegates는 iOS 13부터 여러개의 Scene을 사용하기 위한 목적으로 UI LifeCycle을 AppDelegate 대신 처리하게 되었습니다. 

 

만약 위에 SceneDelegate 대신 iOS 12 이전 처럼 AppDelegate를 사용하길 원한다면 

Info.plist-Scene Configuration 속성을 삭제하면 AppDelegate에서 라이프 사이클을 처리하게 됩니다. 

 

정리

코드를 다 외우기 어렵다고 생각했는데, SceneDelegate에서 직접 로그를 찍어보니 생각보다 직관적이어서 앱의 상태에 따라 필요한 리소스, 메모리 관련 처리를 하는 것에 대한 해상도가 높아진 것 같습니다. 

 

 

레퍼런스

https://developer.apple.com/documentation/uikit/managing-your-app-s-life-cycle

 

Managing your app’s life cycle | Apple Developer Documentation

Respond to system notifications when your app is in the foreground or background, and handle other significant system-related events.

developer.apple.com

https://blog.naver.com/doctor-kick/222423840595

 

[iOS] 앱의 생명주기(LifeCycle) AppDelegate

생명주기 (Life Cycle)이란? 생명주기라는 것은 앱의 최초 실행부터 앱이 완전이 종료되기까지 앱이 가지...

blog.naver.com

https://medium.com/hcleedev/swift-swiftui-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-appdelegate-scenedelegate-%EB%A7%8C%EB%93%A4%EA%B8%B0-4fa2d85191e

 

Swift: SwiftUI 프로젝트에 AppDelegate, SceneDelegate 만들기

AppDelegate와 SceneDelegate 만드는 법, 그리고 그 두 파일 없이도 대응하는 법을 알아보자

medium.com