공식문서로 알아보는 Window, Scene
iOS application에서 화면을 나타내는데 중요한 역할을 하는 window와 scene에 대해 알아봅시다.
scene을 알아보기에 앞서 먼저 window부터 알아보자
window는 애플리케이션 user interface의 전반적인 presentation을 처리한다.
window는 view(및 자체 view controller)와 함께 작동하며 사용자에게 표시되는 view 계층 구조와의 interaction 및 변경사항을 관리한다.
window object는 app의 콘텐츠를 담는 역할을 하며, screen은 기본 디스플레이의 특성을 app에 알린다.
모든 iOS 기반 기기에는 기본 화면을 나타내는 UIScreen
object가 하나 이상 있으며, 추가 screen object는 추가로 연결된 디스플레이를 나타낸다.
외부 디스플레이가 기기에 연결되어 있으면 앱이 두번째 window를 생성하여 해당 디스플레이에도 콘텐츠를 표시할 수 있다.
UIWindow
object는 자체적으로 표시되는 콘텐츠를 제공하지 않고, window의 모든 visible contents는 app의 Storyboard에서 구성하는 root view controller에 의해 제공된다.
window의 visible contents가 되는 root view controller를 지정하는 방식은 Storyboard, 혹은 프로그래밍 방식으로도 지정할 수 있는데, 먼저 일단은 window에 대해 좀 더 알아보자
iOS App에서의 window의 역할
iOS App에서의 window object, 즉 UIWindow
의 인스턴스의 역할을 살펴보자.
- 앱에 표시되는(visible) contents를 포함한다.
- 뷰 및 기타 app object에 touch event 전달하는데 중요한 역할을 한다.
- app의 view controller와 상호작용하여 orientation 변경(화면 회전)을 처리한다.
UIKit
에서 event를 수신하고, 관련 event를 root view controller 및 관련 view에 전달한다.
UIKit
은 사용할 수 있는 initial window를 제공하며, 필요에 따라 추가 window를 만들 수 있다.
이러한 역할을 하는 window에는 콘텐츠를 나타내며 view의 집합을 관리하는 root view controller 객체가 있다.
대부분의 iOS App은 life time동안 하나의 window만 생성하고, 사용한다.
window는 기기의 전체 메인 screen에 표시되며, Storyboard 파일에서 load되거나 application의 life time초기에 프로그래밍 방식으로 생성된다.
window 와 관련된 작업
대부분의 application에서 application이 window와 interact하는 때는 application을 시작할 때(startup)이지만, 몇몇 application과 관련된 일을 수행하기 위해 window object를 이용하기도 한다.
하지만 application의 window object를 이용해 몇가지 application과 관련된 작업을 수행할 수 있다.
- window object를 사용해 point, retangle을 window의 local 좌표계로 변환하거나, window 좌표계에서 변환할 수 있다.
예를들어 window 좌표로 값을 제공받는 경우 값을 사용하기 전에
특정 view의 좌표계로 변환해야 할 수 있다.
Convering Coordinates in the View Hierarchy - window notification을 사용해 window 관련 변경사항을 track할 수 있다.
window가 표시되거나 hidden될 때 또는 key status를 수락하거나 거부할 때 window에서 notification을 생성한다.
UIWindowScene (iOS 13.0+)
iOS 12 이전 까지는 AppDelegate에서 App,과 UI의 Life Cycle을 담당했다면, iOS 13부터는 UIWindowScene
이라는 개념이 도입되었다.
iOS13 부터는 UIKit
은 UIWindowScene
객체를 사용해 앱 UI의 각 인스턴스를 관리할 수 있게 되었다.
scene
에는 UI 의 한 인스턴스를 presenting(표시)하기 위한 window와 view controller가 포함된다.
scene object는 사용자의 기기에 표시되는 window와 scene의 life cycle을 관리한다.
각 scene 에는 해당하는 UIWindowSceneDelegate
object가 있으며, 이를 사용해 UIKit
과 app간의 interaction을 할 수 있다.
scene의 상태가 변경되면, scene object는 해당 delegate object에 변경사항을 알리며, 알림을 받는 delegate object는 UIWindowSceneDelegate
프로토콜을 채택하고 있어야한다.
우리가 iOS app template을 사용해 프로젝트를 생성하면 생기는 SceneDelegate.swift
가 UIWindowSceneDelegate
프로토콜을 채택하고 있는 것 역시 scene object로 부터 변경사항을 받기 위해서이다.
scene은 또한 등록된 observer에게 notification을 post하는데, delegate object 또는 Notification Observer를 사용해 변경사항에 응답할 수 있다.
Apple 공식 문서에서는 사용할 window scene object를 직접 생성하지 말고
대신 앱의 Info.plist
에서 configuration time에UIWindowScene
object로 사용할 class의 이름을 지정해 사용하도록 가이드하고 있다.
UIKit
새로운 scene을 생성하기전에 이 메서드를 호출해
scene의 type, scene을 관리하는데 사용하는 delegate object, 표시할 초기 view controller가 포함된 Storyboard가 포함된 UISceneConfiguration
객체를 반환한다.
만약 Info.plist
에서 Scene Configuration을 설정해주지 않았거나, Scene Configuration을 동적으로 변경하고 싶을 때는 AppDelegate.swift
에서 해당 메서드를 구현해주면 된다.
만약 이 메서드를 구현하지 않을 경우 Info.plist
에 Scene Configuration 해당 data를 지정해주어야한다.
iOS App에서 window가 표시되기 까지
Xcode에서 iOS app template에서 Storyboard를 이용해 프로젝트를 생성하면 app의 window를 명시적으로 생성하거나, load할 필요가 없다.
Info.plist
Scene Configuration에서 scene의 window의 root view controller로 지정할 view controller를Storyboard Name의 value로 지정되어있는 Storyboard에서 찾는다.
위와 같은 과정을 통해 Storyboard를 식별하면 iOS에서 몇가지 설정 작업을 수행한다.
lannch time에
- window를 인스턴스화 하고,
- Main Storyboard를 load하고, 초기 View Controller를 인스턴스화 한다
- 새 view controller를 root view controller의 프로퍼티에 할당하고 window를 표시한다.
key window에 관하여
key window는 뭘까?
하나의 scene에는 여러개의 window가 존재할 수 있다.
key window는 keyboard 및 터치와 관련 없는 이벤트를 수신하며, 한번에 하나만 key window가 될 수 있다.
touch event는 touch가 발생한 window에 전달된다.
링크: https://developer.apple.com/documentation/uikit/uiwindow#1652662
UIWindow
인스턴스의 초기상태는 isHidden
은 true
이고, keyWindow
가 아닌 상태이다.
window.makeKeyAndVisible()
UIWidow
인스턴스의 makeKeyAndVisible()
메소드를 호출함으로써 해당 window 인스턴스의 isHidden
속성을 false
로 설정하고, 해당 window 인스턴스를 keyWindow
로 설정해줄 수 있다.
View Controller와 window의 관계
application UI의 각 scene에는 window object와 하나 이상의 view object가 포함된다.
window는 UI를 위한 보이지 않는 container역할을 하며, view의 최상위 contianer역할을 하고, 이벤트를 view로 routing한다.
view는 text, image, 및 custom content를 그리는 등 사용자에게 화면에 표시되는 실제 콘텐츠를 제공한다.
view는 수명이 긴 object이기 때문에 scene의 전체 UI를 해제할 때만 view를 해제할 수 있다.
새로운 콘텐츠나 정보를 표시하려는 경우 해당 window의 view를 변경할 수 있다.
view를 효과적으로 관리하고 window에서 view를 쉽게 추가 및 제거할 수 있도록UIKit
은 view controller를 제공한다.
view controller는 view의 집합을 관리하며 해당 view의 정보를 최신 상태로 유지한다.
위 그림처럼 각 window에는 root view controller가 있으며, 이 view controller를 사용해 window의 초기 view set을 지정할 수 있다.
해당 view set을 변경하려면 UIKit에 추가 view controller를 표시하거나 해제하도록 지시한다.
UIKit은 한 view set에서 다른 view set로 transition을 처리하고, view controller object를 통해 앱의 전체 인터페이스를 관리한다.
따라서 view controller는 UI를 구현하는 데 중요한 역할을 한다.
Assign a root view controller to window
root view controller는 window의 초기 navigation model을 정의한다.
scene 기반 app의 경우 root view controller는 scene의 storyboard 파일의 initial view controller이다.
프로그래밍 방식으로 window를 생성하는 경우 window를 표시하기 전에 window의 rootViewController
속성에 값을 할당해야한다.
프로그래밍 방식으로 window를 생성하고 app의 windowScene
object에 연결하는 과정을 한번 살펴보자
먼저
app의 configuration time에 Info.plist
설정해둔 Scene Configuration으로 scene이 생성되고, app이 사용자 인터페이스 인스턴스를 생성할 때
Info.plist
의 Delegate Class Name
로 지정해둔 아래의 SceneDelegate의
scene(_:willConnectTo:options:)
메소드가 호출된다.
아래와 같이 파라미터로 넘어오는 app에 현재 연결중인 scene object를 UIWindowScene
으로 type casting을 해준다.
일반적으로 사용자 또는 app이 요청하는 app UI의 각 인스턴스에 대해UIKit
은UIScene
객체 대신UIWindowScene
객체를 생성한다고 한다.
링크 : https://developer.apple.com/documentation/uikit/uiscene#overview
func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard let windowScene = scene as? UIWindowScene
else { return }
}
그 다음 window
object를 생성하고, windowScene
object와 연결하기 위해 아래의 생성자를 이용해 window
object를 생성한다.
해당 생성자로 생성한 window
object는 windowScene
의 windows
속성에서 접근할 수 있다.
생성자 문서 링크 : https://developer.apple.com/documentation/uikit/uiwindow/3197961-init
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
object의 root view controller를 지정한다.
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 = SomeViewController()
}
그 다음 해당 window
object를 key window로 만들고, isHidden
속성을 false
로 만들기 위해 window
object의 makeKeyAndVisible()
메소드를 호출한다.
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 = SomeViewController()
window.makeKeyAndVisible()
}
마지막으로 현재 windowScene
과 연결된 main window를 위에서 생성한 window
로 설정해준다.
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 = SomeViewController()
window.makeKeyAndVisible()
self.window = window
}
마무리
여기까지 window
와 scene
그리고 앱의 첫 화면을 로드할 때 까지의 일어나는 일들의 일부를 살펴보았습니다.
개념을 알아내기 위해 정말 많은 문서를 보며, 야크 털을 깎는 듯한 기분이 들었지만 기본이 되는 개념을 알아낸 것 같아 기쁘네요!💪
아직 모르는 것이 많고 알아가는 과정입니다. 잘못된 것이 있다면 댓글로 남겨주신다면 감사하겠습니다! 😊
참고