2023. 12. 17. 02:34ㆍApple/UIKit
UIKit 의 Scene Delegate
에서 초기 화면 접근시 로직 설정(rootViewController
) 혹은 키보드, 내비게이션 화면 이동 등 설정을 하곤 했다. 여러 문서와 글을 검색하고 읽었을때, Scene Delegate
는 iOS 13 부터 나온 거라는 사실을 알 수 있다.
그 전에는 App Delegate
에서 앱의 환경설정, 메모리 관리, 앱이 시작되고, 종료될 때의 설정, 화면 전환 및 scene 의 생명주기 관리까지 한 것 같다.
scene delegate 와 app delegate
Scene Delegate
가 없었을때는 App Delegate
에서 화면 관리나 앱의 생명주기를 설정을 했다는 건데, 공식문서를 살펴보면 app delegate
와 Scene Delegate
는 class
다. 클래스는 참조(reference, 주솟값을 참조하다의 그 참조 맞다.) 타입이고, 단일 상속- Inheritance
(유산 상속 받다의 느낌이다.)이다. Apple 프레임워크의 큰 형태들은 클래스로 구성되어 있다.
Xcode 프로젝트를 열어, AppDelegate, SceneDelegate 파일을 보면 class 타입이고, 각각의 delegate 를 채택한다, 공통적으로 UIResponder 라는 class 타입을 상속받는다.
NOTE- UIResponder
이벤트(어떤 행위에 대한 메소드를 처리해주는 것) 에 응답하고 처리하기 위한 추상 인터페이스다.
@MainActor class UIResponder : NSObject
UIResponder 가 처리하는 이벤트에는 터치 이벤트, 모션 이벤트, 원격 제어 이벤트, 프레스 이벤트 등 여러 종류가 있다
iOS 12 까지는 app delegate
에서 window
하나를 만들어서 관리
iOS 13 이후, scene 이 생기고 ipadOS 경우 여러 개의 창 Split View 사용이 가능해졌다.
(window 에 대한 설명은 UIWindow 에서 정리한 적이 있다.)
지금의 app delegate
를 보면 위에 @main
이라는 표시가 있다. 애플리케이션의 진입점이자, 최상위 코드이다. main
은 또한 app
이 초기화되고 실행되는 것이다.
정리
iOS 13 이전에는 App Delegate 에서 UI LifeCycle(사용자 인터페이스 생명주기) 에 대한 부분을 했으나, 그 이후로는 Scene Delegate가 하게됨. App delegate 는 Scene session 생성하거나 삭제되는 것을 관리하는 session lifecycle 의 역할이 추가되었다.
App delegate 가 맡게 된 역할
1. 데이터 구조를 초기화
2. 앱의 Scene을 환경설정(Configuration)
3.앱 밖에서 발생하는 것들 대응 ( 배터리 부족, 다운로드 완료..등)
4. 앱 자체 타겟하는 이벤트 대응
5. apple 의 push notification service 와 같이 실행시 요구되는 모든 서비스를 등록하는 일
등등..
App Delegate
에 대해서 더 자세히 찾아보고 정리하고 싶으나, 원점으로 돌아와 Scene Delegate
에 대해서 자세히 얘기해보려고 한다. 다음에 상기했다가 둘의 특징도 다시 정리해 봐야겠다.
공식문서를 기반으로 정리를 했으며, 나중에 추가적으로 예시 코드나 정보를 더 넣으려고 한다.
(퇴고는 신경써서 잘하자 라고 생각한다. 수정중이라는 꼬리표를 단 놈들도 하나씩 정리를 더 해보고 읽어봐야겠다.)
UISceneDelegate 의 형태
@MainAction
protocol UISceneDelegate
Scene 내에서 발생하는 수명 주기(LifeCycle) 이벤트에 응답하는 데 사용하는 핵심 방법이다.
정확히는 App LifeCycle Event 다.
+ 추가 ) 이러한 App LifeCycle Event 는 App Delegate 에서 관리하는 것인데, 조만간 App Delegate 에 관해 정리를 해보고 링크를 걸어놔야겠다. (아래 애플의 앱 수명주기 그림도 App Delegate 와 연관이 있다고 보면 되겠다. )
씬델리게이트(Scene Delegate)의 정의가 수명주기 이벤트에 응답하는데 사용하는 방법이다보니 부차적으로 첨부하게 되었다.
애플리케이션 자체의 생명주기와 관련된 작업을 처리하는 곳 -> AppDelegate
각 창에 대한 생명 주기 이벤트를 처리하며, 창이 활성화 비활성화될 때 실행할 코드를 정의하는 곳,
새로운 창 열거나 닫을 때와 같은 멀티 창 관련 작업 처리
-> SceneDelegate
💡 여기서 잠깐, 생각해 볼 점
View LifeCycle - view Controller 에서 수명주기와는 또 다르니, 용도에 맞게 구분해서 잘 써야겠다.. 나중에 한번 비교해봐야겠다.
https://playground-coding.tistory.com/84
그래서, Scene이 뭘 하는걸까?
앱 UI의 여러 인스턴스(개체, 객체)를 동시에 관리하고 리소스를 적절한 UI Instance 로 보낸다.
UIKit은 UIWindowScene
객체를 사용해, 앱 UI 의 각 인스턴스를 관리해준다. Scene에는 UI 의 한 인스턴스를 표시하기 위한 windows
와 view controllers
가 포함되어 있다. 각 scene 에는 UIKit 과 앱 간의 상호 작용을 조정하는 데 사용되는 해당 UIWindowSceneDelegate
개체도 있다.
Scene은 서로 동시에 실행되어 동일한 메모리와 앱 프로세스 공간을 공유한다. 결과적으로 단일 앱(Single app)에서는 동시에 여러 장면과 scene delegate(화면 위임자(대리자)) 객체가 활성화될 수 있다.
NOTE - UIWindowScene
앱에 대한 하나 이상의 창(window)을 관리하는 Scene 이다.UIApplicationDelegate 객체에서 새 Scenes의 구성을 관리한다.
@MainActor class UIWindowScene: UIScene
class - UIScene
앱 사용자 인터페이스의 한 인스턴스를 나타내는 개체다.
@MainActor
class UIScene: UIResponder
UIKit 은 사용자나 앱이 요청하는 앱 UI 의 각 인스턴스에 대한 화면 객체를 생성한다.
일반적으로 UIKit 은 UIScene 객체 대신 UIWindowScene 객체 를 생성하지만, Scene 에 대한 정보에 액세스(접근)하려면 이 클래스의 메서드와 속성을 사용한다.
모든 Scene 객체에는 UISceneDelegate 프로토콜을 채택하는 객체인 연관된 delegate(위임) 객체가 있다. scene 의 상태가 변경이 되면, scene 객체는 delegate 객체에 알리고 등록된 observer(관찰자)객체에 적절한 알림을 게시한다. Scene 상태의 변화에 응답하려면 delegate(대리자) 객체와 알림을 사용해야한다.
예를 들어 scene이 background 로 이동하는 시기를 결정 하는데 사용한다.
scene 객체를 직접 생성하지 않는다.
UIApplication의 requestSceneSessionActivation(_:userActivity:options:errorHandler:)
를 호출하여 코드베이스로 UIKit 앱의 Scene의 객체를 생성하도록 요청할 수 있다.
UIKit 은 또한 사용자 상호 작용에 응답해 Scene을 생성한다. 앱의 Scene 지원을 구성할 때 UIScene 객체 대신 UIWindowScene 객체를 지정한다.
NOTE
requestSceneSessionActivation(_:userActivity:options:errorHandler:) 는 Deprecated 되었음으로, activateSceneSession(for: errorHandler:) 를 사용해야한다.
UIKit 은 또한 사용자 상호 작용에 응답해 Scene을 생성한다. 앱의 Scene 지원을 구성할 때 UIScene 객체 대신 UIWindowScene 객체를 지정한다.
UIScene 의 Delegate 가 바로 UISceneDelegate 다
var delegate: UISceneDelegate? { get set }
시스템은 앱의 Info.plist 파일에 제공하거나 Scene 장면을 구성할 때 app delegate 가 지정하는 클래스 이름을 기반으로 기본 delegate 객체를 생성한다. 필요에 따라 나중에 이 기본 delegate(대리자)객체를 변경할 수 있다.
스토리보드없이 코드베이스(programmatically)로 UI 컴포넌트들을 그리고 싶다면,
1. Main.storyboard 를 삭제 하고 (Move to Trash)
2. Info.plist 설정에서 storyboard Name의 Main 이라는 이 항목을 아예 삭제한다.
a. Main storyboard file base name - Main
b. Storyboard Name - Main
3. SceneDelegate 설정
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) // SceneDelegate의 프로퍼티에 설정해줌
let mainViewController = ViewController() // 맨 처음 보여줄 ViewController
window?.rootViewController = mainViewController
window?.makeKeyAndVisible()
...
}
}
4. 그리고 나타내고 싶은 view 를 UIViewController 로 생성하면 스토리보드없이 사용가능해진다.
import UIKit
class CustomViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGreen
let title = UILabel()
title.text = "변경 뷰"
}
}
⚠️ 유의
project 명의 TARGET 으로 가서 메뉴 탭의 Info.plist 파일에서의 storyboard Name 의 Main도 지워줘야 할 것이다.
UI Scene Delegate 의 정의
UISceneDelegate 객체를 사용해 앱 사용자 인터페이스(UI)의 한 인스턴스에서 수명 주기 이벤트를 관리한다.
이 인터페이스는 Scene이 foreground 에 들어가 활성화 될 때와 background 에 들어갈 때를 포함하며, Scene 이 영향을 미치는 상태와 (화면)전환에 응답하기 위한 메서드를 정의한다.
이러한 전환이 발생할 때 대리자(Delegate)를 사용해 적절한 동작을 제공할 수 있다.
예를 들어, 중요한 작업을 완료하고 앱이 백그라운드로 들어갈 때 데이터를 저장하고 앱을 조용하게 한다.
- UISceneDelegate 객체를 직접 생성하지 마라. 대신 Scene 에 대한 구성 데이터의 일부로 사용자 정의 Delegate(대리자) class 이름을 지정해라.
⇒ 이 정보는 앱의 Info.plist 파일이나 app delegate의application(_ : configurationForConnection: options:)
메서드에서 반환하는UISceneConfiguration
객체에 지정할 수 있다.
Connecting and disconnecting the scene (화면을 연결하고 끊을 때 사용하는 메서드)
- 앱에 Scene 의 추가에 대해 delegate 에 알리는 것
- UIKit 이 앱에서 Scene 을 제거했음을 delegate 에게 알린다
- UIKit 이 Scene(장면, 화면)을 생성한 이유에 대한 정보를 포함하는 데이터 객체다.
Foreground 전환 - 진행 중인 화면(사용자가 앱을 열어 바라보는 화면)
- Scene 이 foreground(앞단)에서 실행되기 시작하고 사용자에게 표시될 것임을 delegate(대리자)에게 알린다.
- Scene이 활성화되어 이제 사용자 이벤트에 응답하고 있음을 Delegate(대리자)에게 알린다.
background 로 전환
- 사용자가 앱을 종료치 않고 내려놓고 전화를 받거나 다른 앱으로 이동할 때 여전히 화면에 대기 중인 상태
- 장면이 활성상태를 종료하고 사용자 이벤트에 대한 응답을 중지하려고 함을 대리자(Delegate)에게 알린다.
- 장면이 백그라운드에서 실행 중이며 더 이상 화면에 표시되지 않음을 대리자(Delegate)에게 알린다.
Url 열기
- 대리자(delegate)에게 하나 이상의 Url 을 열도록 요청한다.
지속적인 사용자 활동(Continuing user activities)
- Handoff 관련 데이터를 수신할 예정임을 대리인(Delegate)에게 알린다.
- 지정된 핸드오프 관련 활동을 처리하도록 대리인에게 지시한다.
- 활동을 계속할 수 없다고 대리인에게 알린다.
Saving the state of the scene(Scene 의 상태저장)
NOTE - Restoring Your App’s State 현재 활동을 보존해 사용자에게 연속성 제공
Restoring Your App’s State
지정된 Scene 의 현재 상태를 캡슐화하는 사용자 활동 객체를 반환한다.
func stateRestorationActivity(for: UIScene) -> NSUserActivity?
func scene(UIScene, restoreInteractionStateWith: NSUserActivity)
지정된 활동 개체가 업데이트되었음을 대리인에게 알린다.
func scene(UIScene, didUpdate: NSUserActivity)
참고 문서
https://developer.apple.com/documentation/uikit/uiscenedelegate
https://lena-chamna.netlify.app/post/appdelegate_and_scenedelegate/#AppDelegate와-SceneDelegate
틀린 부분 지적이나, 추가 의견 등의 피드백 댓글 환영입니다!