iOS2022. 6. 15. 10:24

SceneDelegate? 멀티윈도우?

AppDelegate로 관리되던게 어느순간 SceneDelegate란게 나타났다.
iOS13부터 등장한거 같은데...
SI특성상 iOS11부터 지원하는 경우가 많아서 아직까지 SceneDelegate를 사용하는 경우가 없긴 하나 알아두어야 하겠다.

AppDelegate는 iOS12와 이전버전에서 앱의 라이프사이클을 관리하는데 사용된다.
iOS13부터는 일부 역할을 SceneDelegate에 넘겨주게 되며 AppDelegate의 역할은 자연히 줄게 되었다.
AppDelegate는 여전히 앱이 시작되는 시작점을 비롯하여 앱레벨의 라이프사이클을 관리한다.

주요한 3개를 정리해 보면 
1. func application(_: didFinishLaunchingWithOptions:) -> Bool
앱 시작 포인트

2. func application(_: configurationForCOnnecting:options:)-> UISceneConfiguration
새로운 scene/window를 제공하려고 할때 호출됨. 최초에는 호출되지 않음

3. func application(_: didDiscardSceneSessions:)
scene이 종료될때 호출. 사용자가 multitasking이나 코드레벨에서 없애는 경우가 해당된다.


SceneDelegate

화면에 무엇을 보여줄것인지 처리한다.

1. scene(_: willConnectTo:options:)
scene은 하나의 UISceneSession을 갖게 되고 여기에서 처음 이 메서드가 호출된다.
contentView, window생성 그리고 window의 rootViewController를 설정한다.
storyboard를 사용하지 않고 개발하는 경우 여기서 UIWindow를 생성하고 rootViewController생성하는 코드를 직접 작성해야 한다.
storyboard를 사용한다면 특별히 작성해야 할 코드는 없다.

2. sceneWillEnterForeground(_:)
scene이 foreground로 전환될때 호출된다.

3. sceneDidBecomeActive(_:)
scene이 setup되고 화면에 표시될 준비가 완료된 상태에 호출된다.

4. sceneWillResignActive(_:)
active -> inactive 시 호출된다.

5. sceneDidEnterBackground(_:)
foreground -> background시 호출

6. sceneDidDisconnect(_:)
background상태에서 시스템이 자원을 확보하기 위해서 scene을 disconnect할 수 있다.

그렇다면 왜 이렇게 바꿨을까에 대한 생각을 안해볼수가 없지 않나?

이유는 iPad에서 Multiwindow를 지원하면서 나타났다.

멀티윈도우를 지원하려다 보니 AppDelegate가 하나의 UI를 관리하던 체제에서 여러 UI를 관리히야 하게 되었고 이 때 UI를 Scene단위로 구분하게 된것이다. 따라서 AppDelegate는 UI관련 처리를 하지 않게 되었고 이런 부분은 SceneDelegate에서 해야 하게 되었다.

멀티윈도우를 지원하지 않을거라면 궂이 SceneDelegate를 사용할 필요가 없다는 것이다.
SceneDelegate를 삭제하는 방법은 다음과 같다.

1. SceneDelegate.swift 삭제
2. UIWIndow를 AppDelegate로 이동
3. Info.plist에서 Application Scene Manifest삭제

AppDelegate는 UI관련 처리를 하지 않는 대신에 SceneSession이 추가되거나 삭제될때 보고를 받게 된다.

Scene은 안드로이드의 Activity가 시스템에 의하여 수거될수 있는것처럼 앱이 background상태일 때 수거될 수 있다.
이 때 해당 화면의 데이터를 보관했다가 나중에 Scene이 다시 새로 생성될 때 화면에 복원해주어야 할 수 있다.
이를 위해 func stateRestorationActivity(for scene: UIScene) -> NSUserActivity?를 제공하며 여기서 관심있는 데이터를 저장했다가 func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) 호출 시 저장했던 데이터로 화면을 복원할 수 있다.

SceneDelegate가 멀티윈도우를 지원하기 위해서 나왔고 따라서 ViewController가 하나만 생성되던 상황이 아닐수 있게 되었다. 이 때 고전적으로 ViewController에서 어떤 데이터가 생성되는 이벤트가 발생하면 그 내용을 화면에 바로 반영하는 방식으로 작업하게 되면 하나의 화면에만 그 내용이 반영되는 경우가 발생할 수 있다.
이를 해결하기 위해서는 데이터가 발생하면 모든 뷰컨트롤러에서 이를 처리하는 방식으로 수정되어야 한다.
3가지정도의 방법이 있다.

1. delegate로 이벤트 발생 시 모두처리
2. notification으로 이벤트 발생 시 모두 처리
3. Swift Combine Framework 사용

notification으로 처리하는것을 예를 들면 데이터가 발생하는 이벤트가 발생하면 바로 화면에 반영하지 않고 이벤트는 모델 컨트롤러에 저장하고 notification을 생성하여 전송한다. ViewController는 notification handler를 작성하고 여기서 모델컨트롤러의 데이터에 접근하여 화면에 반영한다. 그러면 모든 ViewController가 데이터의 변화를 감지하고 화면에 반영할수 있다.

이제 멀티윈도우이벤트를 발생시켜서 두개의 화면으로 나뉘게 하는 방법을 알아볼 차례인데...
아직 이런걸 만들어 볼일이 없어서 나중에 필요가 생기면 알아보기로 하겠다.

Posted by 삼스