[swift] App의 LifeCycle (2)
[swift] App의 LifeCycle (1) ⬇️⬇️⬇️
지난 번에는 WWDC2019에서 발표된 내용에 따라 AppDelegate와 SceneDelegate와 역할 및 LifeCycle을 보았었는데요!
오늘은 scene의 상태 변화(state transition)에 대해 알아보고, 실제 앱에서 실행하면서 어떤 메서드들이 호출되는지 알아볼게요.
공식 문서 보기 ⬇️⬇️⬇️
scene은 처음에 Unattached된 상태입니다.
그 후 유저가 요청한 scene은 화면에도 보이고 메모리에도 올라가는 Foreground로 들어갑니다. foreground는 Inactive와 active 상태가 있는데, Inactive 상태를 거쳐 active 상태로 들어갈 수 있어요.
그렇지만 우리가 1개의 앱을 계속 사용하지는 않져? 만약 다른 앱을 사용하거나, 홈화면으로 돌아가거나 등등의 이벤트로 인해 Background 상태로 돌아갑니다. Background는 메모리에는 올라가 있지만, 화면에는 보이지 않는 상태를 말해요. (이 때도 inactive상태를 거쳐 Background로 돌아가요. )
Background 상태로 접어든 앱은 Suspended(대기상태)로 있기도 하고, 특정 작업이 필요한 경우에는 백그라운드에서 작업이 이루어지는 경우도 있어요. 사진을 업로드 한다거나 타이머가 돌아간다거나 등등의 작업을 백그라운드에서 할 수 있져. 그러다가 작업이 끝나면 다시 Suspended 상태가 되어 대기를 하게 됩니당.
그럼 이제 실제로 앱 실행 과정에서 어떤 메서드들이 호출되는지 볼까요?!!
우선 프로젝트를 하나 만든 후, AppDelegate.swift 파일과 SceneDelegate.swift 파일에 전부 print(#function)을 해주어 언제 메서드들이 불려지는지 체크해볼게요!
지난 번에 사용했던 ViewController 프로젝트를 그대로 사용할거라 ViewController의 라이프 사이클도 함께 출력될 거에요!
ViewController의 LifeCycle ⬇️⬇️⬇️
우선 프로젝트의 시뮬레이터를 실행하자마자 아래와 같이 메서드들이 호출되네요잉?
이제 하나씩 알아볼게요!
//AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
앱이 로드되면서 가장 먼저 호출되는 메서드입니다.
로드 되기 전에 어떤 작업이 필요하다면 여기서 해주는 게 좋겠져?
//SceneDelegate.swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)
앱이 UI의 인스턴스를 생성할 때, 호출되는 메서드로 delegate에게 이 scene을 앱에 추가하라고 말한대요.
유저나 앱이 UI의 새로운 인스턴스를 요청하면 UIKit가 적절한 scene 객체를 생성하여 앱과 연결시키구요.
새로운 scene 추가를 하거나, 화면에 보여질 어떤 것을 로드할 때 이 메서드를 사용하면 된다느군여.
(제가 이해한대로 단순하게 말하면!) 그냥 유저/앱이 이 scene을 화면에 띄워달라고 하면 기특한 UIKit가 자동으로 scene에 대한 객체를 만들어 화면에 뙇! 띄어준다는 말 같아요!
그러니까 이제 viewDidLoad와 viewWillAppear 메서드가 불리면서 화면에 나타나요.
다음으로는 아래 메서드들이 호출되는데여!
//SceneDelegate.swift
optional func sceneWillEnterForeground(_ scene: UIScene)
메서드 이름 자체로 이미 어느 정도 이해가 갈 것 같지만,
sceneWillEnterForeground는 UIKit가 Foreground로 가기 직전에 호출하는 메서드입니다. 새롭게 생성되어 연결될 scene이나, Background에 있다가 유저의 액션에 따라 Foreground로 넘어올 scene이 있을 때 이 메서드가 불려진대요.
//SceneDelegate.swift
optional func sceneDidBecomeActive(_ scene: UIScene)
그 다음, scene을 화면에 나타나게 할 때 sceneDidBecomeActive가 불려집니다. UIKit은 씬(scene)에 대한 인터페이스를 로드한 후지만, 해당 인터페이스가 화면에 나타나기 전에 이 메서드를 호출합니다. 뷰의 내용을 새로 고치거나, 타이머를 시작하거나, UI의 프레임률을 높이는 데 사용합니다.
그 후 제가 홈바를 통해 앱 스위쳐(App Switcher)로 넘어가면? (또는 홈버튼 더블클릭)
//SceneDelegate.swift
optional func sceneWillResignActive(_ scene: UIScene)
위와 같이 Active 상태를 끝낼 것이라는 메서드가 불리네요.
이 메서드는 일시적인 방해(알림창 같은)가 생길 때 호출되거나 앱이 Background 상태로 접어들기 전에도 불려진대요.
이 방법을 사용하여 인터페이스를 조용하게(?)하고, 유저와의 상호 작용을 중지하도록 준비합니다. 특히 진행 중인 작업을 일시 중지하고 타이머를 비활성화하며 프레임률을 낮추거나 인터페이스 업데이트를 모두 중지할 수 있습니다. 하던 게임들도 일시 중지되구요. 앱은 Background 또는 Foreground로 다시 전환되기를 기다리는 동안 최소한의 작업만 하고 있을 것입니다.
만약 이 때 유저가 작성하고 있던 정보가 있었다면 어떻게 할까요? 이 메서드를 통하여 데이터가 저장되게 할 수도 있습니다. 그러나 오로지 이 메서드에만 의존해서는 안됩니다. 적절한 시점에 데이터를 저장할 수 있도록 viewcontroller에서 작업을 해야 한대요.
제가 앱 스위쳐에서 만약 다른 앱을 선택하면 어떻게 될까요?
아래 메서드가 호출 됩니당.
//SceneDelegate.swift
optional func sceneDidEnterBackground(_ scene: UIScene)
이름 그대로 Background 상태로 접어들어 더 이상 화면에 나오지 않는 상태를 말해요.
백그라운드 상태로 접어들면서 메모리 사용을 줄이고, 공유된 resources를 비우게 됩니다. 이 메서드가 리턴(?)한 직후, UIKit는 앱 스위쳐에서 보이는 화면을 위해 스냅샷을 찍어놓는데요. 우리가 앱 스위쳐에서 봤던 화면들은 UIKit가 찍어놓은 스냅샷이었군여! 유저의 민감한 정보가 포함되지는 않았는지 확인도 해야합니다.
그리고 다시 앱 스위쳐를 통해 원래의 앱으로 돌아오면?
다시 Foreground 상태로 왔다가 active 상태가 되져.
앱 스위쳐에서 앱을 위로 날려서 꺼버리면 어떻게 될까요?
앱 스위쳐를 하면서 sceneWillResignActive가 호출되는 것은 위와 동일한데요.
아래 두 메서드를 보니 뭔가 연결이 끊기고, session이 끝나는 것 같아요.
//SceneDelegate.swift
optional func sceneDidEnterBackground(_ scene: UIScene)
씬(scene)을 메모리에서 제거하기 전 마지막 정리를 수행하려면 이 메서드를 사용한대요. 예를 들어 파일 또는 공유 리소스에 대한 참조를 해제하고 사용자 데이터를 저장하는 등!
scene을 제거하는 것은 결국 그 scene을 끝내려는 것이고, 사용자가 앱 스위쳐에서 씬(scene)을 명시적으로 닫으면 UIKit이 씬(scene) 연결을 끊습니다.
//AppDelegate.swift
optional func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>)
그리고는 AppDelegate에 있는 위 메서드가 마지막으로 호출되는군요!
scene과 관련된 세션 객체들을 전부 버려버리기(discard) 전에 이 메서드가 호출되는데, 만약 앱이 작동 중이 아니었다면, 앱을 시작한 다음에 이 메서드를 호출한대요 (어떻게??)
UIKit은 장면을 영구적으로 dismiss할 때만 이 방법을 호출합니다. 시스템이 메모리를 확보하기 위해 scene을 분리할 때는 호출하지 않습니다.
ViewController의 LifeCycle
App의 LifeCycle
어떤 역할인지는 알겠지만, 완벽하게 이해하려면 시간이 많이 필요할 것 같아여ㅠㅠ
오늘도 틀린 게 있으면 언제든 알려주십셔 슨배님덜!