iOS: Application LifeCycle
애플리케이션의 생명주기는 App Launch -> App Visible -> App Recedes into Background -> Resources Reclaimed로 구성된다.
마지막 과정인 Resources Reclaimed 가 어떻게 iOS가 동작하는지에 대한 핵심이다. 자원(Resource)란 CPU time 과 memory 같은 한정된 자원을 말하며, OS는 이런 자원들을 어떻게 할당할지 결정해야 한다. 그렇다면 iOS에서는 무엇으로 우선순위를 결정할까?
가장 높은 우선순위를 가지는 것은 지금 유저에게 보여지고 있는 foreground에서 실행되고 있는 앱이다.
이러한 것을 앱 개발자가 App Lifecycle을 고려해야할까?
내가 만든 앱을 사용하는 유저가 있고, 게임 앱에서 방금 보스를 깨거나, 긴 등록 양식을 작성했다고 가정해보자, 만약 이 앱에 백그라운드에서 돌아가고 있고, iOS에서 앱의 자원을 다른 앱에 재할당(reallocate)하고, 데이터가 저장되어 있지 않다면 유저가 그동안 해왔던 과정이 모두 날아갈 것이기 때문이다.
하지만 어느 시점에 데이터를 저장해야 할까? 아마도 사용중인 앱의 Lifecycle중에서 앱이 백그라운드로 돌아가기 시작할 때일 것이다. 이것이 하나의 예이다.
이전에 Firebase를 사용해서 만든 채팅 앱을 생각해보자. 그때 우리가 제일 먼저 해야할 일은 FirebaseApp.configure()를 application:didFinishLaunchingWithOptions:에 넣는 작업을 통해 앱을 확인(configure)하는 일이었다. 그러고 나서 앱을 실행하기 전에 GoogleService-info.plist를 디스크에서 읽어와 우리의 앱이 실행되는 이벤트에 대응하고 우리의 코드가 실행되는 것을 보증해준다.
그래서 우리는 채팅앱의 어디에서 라이프 사이클 메서드를 찾을 수 있을까?
iOS 13 이후의 버전과 Xcode 11에서 생성된 새로운 앱들은 새로운 iOS 프로젝트를 생성할 때마다 AppDelegate.swift, SceneDelegate.swift 파일을 가진다. 이 두 파일의 차이점이 무엇이고, 그리고 scene이 무엇인지에 대해서 살펴보자.
Xcode 11, iOS13 이전에는 AppDelegate.swift 파일만 존재했다. 이 파일은 iOS 운영체제가 앱의 관점에서 우리가 어느 지점에 있는지를 알려주는 파일이었다. 모든 앱의 라이프 사이클을 AppDelegate.swift 파일에서 관리했다.
하지만 iPadOS와 함께 iOS13를 출시한 이후에는 여러 개의 앱을 한번에 실행할 수 있는 multiple window를 지원하였다. 다른 앱을 실행하는 여러개의 창이 있을 수 있다는 의미이다. 다른 말로 하면, 두 개의 다른 화면(scene)이 존재할 수 있다. 이것이 이제는 프로젝트를 생성했을 때 SceneDelegate.swift파일도 생성되는 이유이다. 각각의 scene에 대해 lifecycle을 관리할 수 있게 해 준다. window 중 하나가 백그라운드 상태로 돌아가면 그 window에 해당하는 SceneDelegate.swift파일이 이를 알려준다. 정리하면, SceneDelegate.swift가 하는 일은 각각의 window당 하나의 scene으로 취급하는 것이다.
이제는 앱에서의 공통적인 이벤트를 AppDelegate.swift 에서 처리하고, 다른 모든 라이프사이클의 콜백은 SceneDelegate.swift에서 처리한다.
그렇다면 AppDelegate.swift에서 처리되는, 앱에서 공통적으로 처리되는 이벤트에는 무엇이 있을까? 실행(launch)이나 network carrier에서 시간 차이를 받는 작업등이 있을 것이다.
SceneDelegate.swift에서 처리되는 작업에는, window가 보이기 시작하거나, 백그라운드로 돌아가는 작업등이 있다.
Apple Developer Documentation
developer.apple.com
여러 개의 ViewController(Multiple ViewController) 마다 하나의 scene을 가지고, 하나의 앱에서도 여러개의 scene을 가질 수도 있다. 그리고 각각의 것들은 라이프 사이클을 가지며 override 할 수 있는 메서드를 가진다.
그럼 우리가 override할 수 있는 메서드 들을 살펴보자.
application(_ application:_ application:didFinishLaunchingWithOptions:) 메서드에서 Firebase를 세팅하고, 새로운 데이터베이스를 사용하는 등 앱을 실행하기 이전에 필요한 작업들을 수행하였다.
우리의 앱이 통화로 인해 백그라운드로 옮겨졌다면, 위의 sceneWillResignActive(_ scene:) 메서드에 코딩을 하는 것이 좋을 것이다. 음악을 재생하고 있었다면, 이 메서드 안에, 음악을 일시정지시키거나, 볼륨을 줄이는 등의 코딩을 하는 것이 좋을 것이다.
sceneDidEnterBackground(_ scene:) 메서드는 앱이 foreground에서 background로 옮겨졌을 때 실행된다. 따라서 이 메서드는 백그라운드로 옮겨지면서 유저의 데이터를 저장하고자 할 때 사용할 수 있을 것이다. scene이 background로 옮겨가기 전에 데이터를 저장하면 데이터를 읽어버리지 않을 것이다.
다른 여러 메서드의 기능은 애플의 공식문서를 참조하자.