[ iOS / UIKit ] UISceneDelegate(에 대해 설명하세요)

2023. 12. 17. 02:34Mobile/UIKit

UIKit 의 Scene Delegate 에서 초기 화면 접근시 로직 설정(rootViewController) 혹은 키보드, 내비게이션 화면 이동 등 설정을 하곤 했다. 여러 문서와 글을 검색하고 읽었을때, Scene Delegate 는 iOS 13 부터 나온 거라는 사실을 알 수 있다.

그 전에는 App Delegate 에서 앱의 환경설정, 메모리 관리, 앱이 시작되고, 종료될 때의 설정, 화면 전환 및 scene 의 생명주기 관리까지 한 것 같다.

scene delegate 와 app delegate

Scene Delegate 가 없었을때는 App Delegate 에서 화면 관리앱의 생명주기를 설정을 했다는 건데, 공식문서를 살펴보면 app delegateScene Delegateclass 다.  클래스는 참조(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 에서 정리한 적이 있다.)

ipadOS 에서 사용가능한 split view ( 위의 점 3개로 조정 가능하다 )

지금의 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

 

App의 LifeCycle 관리 - foreground(진행중인 화면), 앱을 내리고 배경화면 상태인 background 등 Scene 전환을 사용해 여러 작업들을 수행한다.

💡 여기서 잠깐, 생각해 볼 점
View LifeCycle - view Controller 에서 수명주기와는 또 다르니, 용도에 맞게 구분해서 잘 써야겠다.. 나중에 한번 비교해봐야겠다. 
https://playground-coding.tistory.com/84

그래서,  Scene이 뭘 하는걸까?

앱 UI의 여러 인스턴스(개체, 객체)를 동시에 관리하고 리소스를 적절한 UI Instance 로 보낸다.

UIKit은 UIWindowScene 객체를 사용해, 앱 UI 의 각 인스턴스를 관리해준다. Scene에는 UI 의 한 인스턴스를 표시하기 위한 windowsview 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 의 각 인스턴스에 대한 화면 객체를 생성한다.

일반적으로 UIKitUIScene 객체 대신 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(대리자)객체를 변경할 수 있다.

 

Info.plist 안에 있는 UIApplication Scene, 이 부분의 가장 안쪽을 파고 들어가면 SceneDelegate 도 보이고, Storyboard 도 보인다.

 

스토리보드없이 코드베이스(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 delegateapplication(_ : configurationForConnection: options:) 메서드에서 반환하는 UISceneConfiguration 객체에 지정할 수 있다.

Connecting and disconnecting the scene (화면을 연결하고 끊을 때 사용하는 메서드)

Foreground 전환 - 진행 중인 화면(사용자가 앱을 열어 바라보는 화면)

background 로 전환

  • 사용자가 앱을 종료치 않고 내려놓고 전화를 받거나 다른 앱으로 이동할 때 여전히 화면에 대기 중인 상태
  • 장면이 활성상태를 종료하고 사용자 이벤트에 대한 응답을 중지하려고 함을 대리자(Delegate)에게 알린다.
  • 장면이 백그라운드에서 실행 중이며 더 이상 화면에 표시되지 않음을 대리자(Delegate)에게 알린다.

Url 열기

지속적인 사용자 활동(Continuing user activities)

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

 

 


틀린 부분 지적이나, 추가 의견 등의 피드백 댓글 환영입니다!