[WWDC] Architecting Your App for Multiple Windows

[WWDC] Architecting Your App for Multiple Windows

·

4 min read

이 글은 wdc 2019 Architecting Your App for Multiple Windows 보고 생각을 정리한 글 입니다.


🗒 간단 요약

  • ios13 부터 mutifle window 를 적용 함에 따라서 App delegate에서 하던 일을 App delegate가 Scene delegate 나누어서 한다.
  • App life cycle, Scene life cycle 을 자세히 보면 이렇다.
  • Scene 의 sync 를 맞추려면 지금까지와는 다른 구조로 짜야 한다.

자세하게 보도록 하자.

🤔 App degate 와 Scene delegate 가 나뉜 이유

ios12 까지는 process Lifecycle 과 UI lifecycle 을 모두 app delegate 에서 처리했다. 그럼에도 아무런 불편이 없었다. 왜냐하면 window(사용자가 보고 있는 화면)가 한개만 존재했기 때문에 process lifecycle 과 UI lifecycle 사이의 큰 차이가 없었기 때문이다.

ios13에 넘어오면서 apple 은 아이패드에 mutifle window 기능을 추가해 주었다. 이제는 하나의 앱인데 동시에 여러개의 화면을 볼 수 있게 되었다. 그러면서 process lifecycle 와 UI lifecycle 은 정말 다른 개념이 되었고 이제 이것을 나누어서 관리하게 되었다.

이 그림처럼 말이다. Scene Delegate 를 만들고 Scene Delegate 에서 UI lifecycle 을 관리하게 만들었다.

이렇게 책임을 분리하면서, app Delegate 가 저야 할 책임이 한가지 더 생겼다. 바로 Scene 이 생성되고 해지되는 것! 이 역할은 앞으로 Session Lifecycle 에서 관리한다.

♻️ App delegate 와 Scene delegate 의 작동 방식

🏁 App이 켜질 때

app 이 실행하면 call stack 에서 무슨 일이 일어나고 있는지 보자. 1️⃣, 2️⃣ 번 까지는 익숙한 내용이다. 3️⃣ 번 인 configurationForSession 이 실행 되었는데 아직 Scene Session 이 생성되지 않았다. UI Scene 을 부르기 전에 UI Scene configuration을 확인한 후 화면을 생성해야 한다. 그래서 4️⃣ 번 에서 UI Scene Configuaration 을 확인한다.

무슨 말인지 헷갈려서 작업 중이던 프로젝트의 app Delegate 파일을 열어 보았다. 이미 자동으로 저 메서드가 구현되어 있다.

이렇게 메서드에서는 어떠한 scene delegate, storyboard를 사용할 것인지 파라미터로 정해 줄 수가 있다. 이렇게 코드로 정의하는 방법이 있고 info.plist 파일로 정의하는 방법이 있다. 아마도 이 부분을 수정하면 되는 것 같다. (확실하지 않음.)

5️⃣ 번 상태에서는 아직 화면이 보이지 않지만 6️⃣ 번 에서 willConnectToSceneSession 을 호출하고 7️⃣ 번 에서 didConnectToSceneSession 이 호출 되고 나면 비로소 화면이 보인다!

🏁 App이 꺼질 때

이제 앱이 실행되다가 사용자가 앱을 switcher 로 보내고 홈 화면에 들어갔다고 가정해보자. 1️⃣ willResignActive 가 호출 된다. 2️⃣ didEnterBackground 가 호출 된다. 3️⃣ didDisconnect 가 호출 된다.

sceneDidDisconnect 가 호출 됐다는 것은

  • 시스템은 Scene 에 연결 되어 있다.
  • 아마도 언제든 불릴 수 있다.
  • 연관한 resources 를 해지한다.
  • Scene 은 아마도 돌아 올 것이다.

여기서 사용자가 아예 앱의 swap 해서 제거하는 경우 1️⃣ didDiscardSceneSession 이 호출 된다.

didDiscardSceneSession 이 호출 됐다는 것은...

  • 영구적으로 세션을 제거 한다.
  • 연관한 정보를 지운다.
  • 다음 런치된 후에나 불릴 수 있을 것이다.

🏗 Sync 를 위한 Architecture

🌱 state restoration 상태 복구 설정

우리가 여행을 가기 위해 다양한 여행 계획을 mutifle window 기능을 활용해서 짜고 있었다. 그러다 창을 닫았다가 켰는데... 맨 처음화면이 나오면? 그건 좋은 사용자 경험이라고 볼 수 없다. 전에 작업하던 창이 나와야 한다. 이걸 어떻게 구현할 수 있을까?

state restoration (상태 복구)를 통해 해보자

💿 Per-Scene State Restoration

ios13 에서는 scene 기반의 state restoration API를 제공해 준다. 이 API는 view hierarchy를 encoding 하는 것이 아니라 window를 다시 만들수 있게 해준다.

NSUserActivity 를 기반으로 두고 있어서, 그냥 같은 뷰를 다시 실행해 주는 것 뿐만 아니라, 어디에 포커스가 가 있었는지, 치다만 텍스트가 있었던 건지 그런 것 까지 복구를 해주는 모양이다.

코드를 보자 stateRestorationActivity 는 앱이 실행되었을 때의 현재 상태를 저장해 주는 메서드 이다. scene 은 scene 을 생성할 때 부르는 메서드이다.

stateRestorationActivity 로 scenedml state 를 저장해 두었다가 새로운 scene 을 생성할 때 작성된 if 문을 통해서 stateRestorationActivity 가 있으면 data 를 가져와서 scene 을 만들고 아니면 새로운 scene 을 만드는 식이다.

🎵 Keeping Scenes in Sync

Scene 이 여러개가 되었고 같은 화면을 보고 있을 때 우리는 싱크를 맞춰 주어야 한다.

Scene 이 하나만 있을 때 처럼 코드를 작성하면 아래와 같은 오류가 나타난다.

Scene 이 업데이트 되지 않는 것이다.

위와 같은 방식으로 코드를 바꿔 주어야 한다.

delegate, notification 또는 새로운 Swift Combine framework 사용하는 방법이 있다.

우선 여기에서는 notification과 enum 을 활용한 방법을 알려 준다.

우선 첫번째 이미지와 같은 코드를 보자. textField에 text를 입력해서 didEnterMessage를 호출하게 되면, 내부에서 뷰를 업데이트 하고 모델도 업데이를 해주는 코드이다. 위의 그림에서와 같이 뷰를 직접적으로 업데이트 해주면, Scene 이 여러개일 경우 오류가 난다.

이제 이 코드가 잘 sync 될 수 있도록 변경해 보자.

chatVC 노란 부분에 있는 코드를 보면 textField에 text를 입력해서 didEnterMessage를 호출하고 Notification Ceter 을 이용해서 모델을 업데이트 시켜 주었다.

UpdateEvent UpdateEvent라는 enum 타입을 만들어 주었다. post 라는 메서드를 만들어서 post 를 호출하면 NotificationCenter 에 self 를 포스팅 해준다. (이렇게 enum 을 만들면, test 하기도 편하고 Model Controller 부분이 깔끔해 지는 것 같다. 아마도😁)

chatMC 모델이 업데이트 되면 뷰에 Notification 을 post 해서 보내 준다.

chatVC 뷰에서 Notification 알림을 받고 UI 를 업데이트 한다.

이렇게 하면 여러개의 Scene 인 경우에도 sync 를 맞출 수 있다.


사실 아이폰의 경우 아직은 mutiple window 를 지원하지 않기 때문에 아이패드 앱을 만들지 않는 이상 App degate 와 Scene delegate 필요한가? 싶긴 하지만, 문서에서는 애플이 그렇게 사용하는 걸 권장 하더라...


참고 자료 developer.apple.com/videos/play/wwdc2019/258