
지금까지 UIKit을 이용할 때 스토리보드를 이용하여 개발을 진행했다. 처음 연습할 때는 뷰에서 제공할 컴포넌트 자체가 많지 않다보니 충분히 괜찮았고, 오토레이아웃을 넣는 것 또한 단지 드래그 몇 번과 클릭 몇 번, 숫자 변경만 해주면 끝이었다. 하지만 점점 연습하는 뷰 위에 올라갈 요소가 많아지면서 점점 스토리코드를 사용하는 비율이 적어지면서 문득 과연 첫 Main 스토리보드까지 어떻게 없애고 어떻게 첫 뷰를 띄워줄까 궁금해졌다.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
let vc = ViewController()
window?.rootViewController = vc
window?.makeKeyAndVisible()
}
[...]
}
코드상으로는 이게 끝이다. 추가적으로 info.plist와 프로젝트에서 info 탭안에서 Main.storyboard를 가리키고 있는데 이 두 개를 제거해주면 된다. 버전이 업데이트돼서 바뀐건지 예전 블로그들을 참고했을 때는 info.plist에 대한 얘기만 나와있어서 시행착오가 있었다.
그런데 그냥 이렇게 짜면 된다 하고 끝이 아니라 UIScene, UIWindow와 더불어, 이 참에 처음 프로젝트를 생성할 때마다 존재하는 AppDelegate.swift와 SceneDelegate.swift 파일에 대해서도 정리하면서 앱의 생명주기에 대해서 알아보려고 한다.
참고(공식문서) : https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle
Respond to system notifications when your app is in the foreground or background, and handle other significant system-related events.
앱의 현재 상태는 앱이 할 수 있는 것과 할 수 없는 것을 결정 짓는다. 예로, 포그라운드 앱은 유저의 관심을 받기 때문에 CPU를 포함한 시스템 자원들에 대한 높은 우선순위를 가질 수 있다. 반대로, 백그라운드 앱은 현재 스크린에 나오지 않기 때문에 최대한 적은 일을 해야한다.
앱의 상태가 변화할 때, UIKit은 사용자에게 적절한 delegate object의 메서드를 이용하여 사용자에게 알린다. :
Note
만약 scene support를 앱 내부에서 활성화했다면, iOS13와 이후에 대해서는 iOS가 항상 scene delegate를 사용할 것이다. 12와 이전에 대해서는 시스템이 app delegate를 이용할 것이다.
만약 앱이 scene을 지원한다면 UIKit은 UIKit은 각각의 scene에 대해 개별적인 life-cycle events를 전달한다. scene은 디바이스에서 실행중인 앱의 UI에 대한 인스턴스를 대표한다. 유저는 여러 scene을 각각의 앱들에 대해서 생성할 수 있고, 이들을 보여주고 가리는 것을 개별적으로 수행할 수 있다. 각각의 scene들은 개별적인 life cycle을 가지고 있기 때문에, 서로 다른 상태로 실행될 수 있다. 예를 들어, 하나의 scene이 foreground로 돌아가는 동안 다른 scene들은 background로 돌아가거나 suspended 상태일 수 있다.
Important
Scene support는 opt-in feature다. 기본적인 support를 위해서, UIApplicationSceneManifest 키를 app의 Info.plist 파일에 추가해라. 자세한 것은 Specifying the scenes your app supports 참고.
"""
여기서 잠깐 한 문단을 빌려 공식문서 내용 정리에 대한 것을 멈추고 UIApplicationSceneManifest에 대해서 알아보자. 공식문서에서는,
"The information about the app’s scene-based life-cycle support." 라고 한다. 추가적으로 해당 키의 존재는 앱이 scene들을 지원하고, 포그라운드와 백그라운드 전환을 위해 app delegate 객체를 사용하지 않는다는 것을 의미한다고 한다.
"""
다음의 figure는 scene의 상태 전환을 나타낸다. 유저나 시스템이 앱에게 새 scene을 요청하면, UIKit은 이를 생성해서 unattached state로 붙인다. 유저가 요청한 scene들은 포그라운드로 빠르게 전환된다. system이 요청한 scene은 일반적으로 백그라운드로 이동하여 event를 처리할 수 있도록 한다. 예를 들어, 시스템은 location event에 대해 처리하기 위해 scene을 백그라운드로 실행한다. 유저가 앱의 UI를 내렸을 때, UIKit은 관련된 scene을 백그라운드 상태로 전환시키며 최종적으로 suspended 상태로 전환시킨다. UIKit은 백그라운드 상태나 suspended 상태에 있는 scene을 어느 시점에서나 연결을 끊음으로써 자원을 회수할 수 있는데, 이 과정에서 scene은 unattached 상태로 돌아간다.

다음의 작업들을 위해 scene transition을 사용해라 :
iOS 12와 이전과 scene을 지원하지 않는 앱에 대해서, UIKit은 모든 life-cycle 이벤트를 UIApplicationDelegate 객체에게 전달함. app delegate 는 모든 앱의 윈도우에 대해서 관리한다. 결과로, 앱 상태는 외부 디스플레이를 포함한 앱 전체의 UI에 영향을 준다.
다음 figure는 app delegate 객체를 포함하는 상태 전환을 나타낸다. 실행 이후로, 시스템은 앱을 UI가 곧 스크린에 올라올지 여부에 따라 inactive나 background 상태로 놓는다. 포그라운드로 실행할 때, 시스템은 앱을 자동으로 active 상태로 둔다. 그 후로, 상태는 앱의 종료 시점까지 active와 background 상태 사이를 반복한다.

다음 작업들을 수행하기 위해서 app transition을 사용해라:
life-cycle 이벤트를 핸들링하는 것에 더해, 앱은 다음 테이블에 나열되어있는 이벤트들에 대해서도 핸들할 수 있어야함. UIApplciationDelegate 객체를 이용해서 대부분의 이벤트를 처리해라. 일부의 경우에 대해서, notification을 사용해서 앱의 다른 파트에 대해서도 처리할 수 있어야한다.

지금까지 앱의 생명주기를 공식문서 해석을 통해 알아봤다. 다음 포스트는 간단하게 여기서 연관된 UIScene, UISceneDelegate, UIApplicationDelegate 등과 같은 객체 및 프로토콜을 정리해보고자 한다.