저번 글에 이어서 유니플로거 프로젝트를 리펙토링....(사실 새로 만드는 중)하고 있다.
이번 글에서는 튜토리얼, 로그인, 회원가입 화면을 새로 개발한 내용을 공유해보고자 한다.
RIBs 적용하기
기본 립 구조는 다음과 같이 구성하도록 목표를 잡고 시작하였다.
처음 앱 실행 시 튜토리얼 수행(?) 여부에 따라 튜토리얼 화면으로 이동하거나 로그인 화면으로 이동되도록 해야 한다.
1. RootRIB
RootRIB은 스플래시 화면을 담당한다. 스플레시 화면은 런치스크린과 바로 이어지는 화면으로 UI 상으로는 런치스크린에서 사용한 이미지를 그대로 들고 있으면서, 앱 시작 전 체크해야 할 로직(권한, 상태 분기 등)을 처리하도록 한다.
일반적으로 UIWindow를 Splash(Root) RIB에서는 앱의 처음 시작을 담당하기 때문에 AppDelegate(또는 SceneDelegate)에서 초기화 및 RootViewController를 지정해 준다. RootRIB에서는 Builder가 LaunchRouting을 반환하도록 하는데, LaunchRouter에서는 우리가 직접 UIWindow를 초기화하던 것을 대신하여 처리해 준다.
정리해 보면 다음과 같은 일을 수행한다.
1. LaunchRouter는 자신의 ViewControllable 즉 RootRIB의 ViewController를 rootViewController로 세팅함
2. interactor를 activate시킴 - Interactor의 didBecomeActive가 호출되게 함.
3. Router의 load 호출 - Router의 didLoad가 호출되게 함.
따라서 AppDelegate에서 해주어야 할 일은 window를 생성해서 LaunchRouter에 전달해주면 된다.
이후 Splash화면에서 해주어야할 일은 사용자가 스플래시 화면을 보았는지 체크 후
didBeconeActive에서 서비스를 통해 체크한 결과를 토대로 튜토리얼 화면 또는 로그인 화면으로 이동하도록 하면 된다.
2. Tutorial RIB
튜토리얼(스토리 소개) 페이지는 아래와 같이 총 세 가지로 이루어져 있다.
각각의 화면을 페이지 뷰컨트롤러를 이용해 처리할 수도 있고, UICollectionView 등으로도 처리할 수 있었지만, 각각을 별개의 화면으로 두고 Routing처리를 어떻게 할지를 고민해보고 싶어 각각의 화면으로 구성하였다.
처음 시도해 볼 만한 방법은 Splash(Root)가 TutorialFirst를 Child로 추가하고 TutorialFirst가 TutorialSecond를 그리고 Second가 Third를 추가하는 방식이 있다.
각각의 화면은 UINavigationController의 Push를 통해 이동하게 되는데, 각각의 Routing을 위해 모든 RIB이 UINavigationController를 들고 있어야 하고, Parent, Child 간의 관계를 기억하고 관리해주어야 하는 문제가 있다.
지금은 화면이 3개이고 각각의 순서나 유무가 변경될 일이 없으므로 큰 문제가 없어 보이지만, 화면이 많을 경우에는 이마저도 수정하고 관리하기 번거로운 상황이 올 것이다.
각각의 RIB이 내비게이션을 관리하는 대신, Tutorial(Nav) RIB이 네비게이션 컨트롤러를 가지고 각각의 튜토리얼 화면들을 관리하도록 하면 더 편할 것 같았다.
TutorialRoot를 Non-Viewable RIB으로 선언한 후 NavigationController를 처음만 Present 하도록 하고 이후에는 푸시하는 로직으로 분기처리하도록 했다. 각각의 TutorialChilds들은 Root의 Listener을 통해 화면 분기 요청을 하여 다음 화면으로 이동하도록 했다.
2.1 cleanUpViews
RIBs 공부하면서 cleanUpViews가 어디에 쓰이는 건지 많이 궁금했었는데, 이번에 정리해 볼 수 있게 되었다. RIB에는 크게 Viewable(View를 포함하는) RIB과 Non-Viewable(뷰 미포함) RIB이 있는데 각 RIB의 라우팅 시 뷰를 추가 및 제거하는 주체가 다르다.
1. ViewableRIB의 경우 ParentRIB의 Router에서 attach, detach로직 수행 중 present, dismiss 등의 처리를 수행한다.
2. Non-Viewable의 경우 ParentRIB은 attach, detach로직만 담당한다. present, dismiss처리는 childRIB에서 담당한다.
TutorialRootRIB의 경우 NonViewable이므로 부모 립이 아닌 자신이 navigationController를 present 및 dismiss 시켜주어야 한다. 대신 부모인 RootRIB에서는 TutorialRootViewControllable를 자신의 뷰컨트롤러에 적용하여 TutorialRootRIB에 Dependency로 전달한다.
TutorialRootRIB에서 해야 할 일은 detach -> Interactor의 willResignActive -> cleanUpViews의 순서의 콜 스택에 따라 present 했던 navigationController를 dismiss 시켜주어야 한다.
나머지 Tutorial(First, Second Third) RIB에 대한 detach 수행은 TutorialRoot RIB이 detach 될 때 함께 수행되므로 걱정하지 않아도 된다.
이제 마지막 튜토리얼에서 회원 가입으로 이동할지의 유무에 따라 SplashInteractor(TutorialRootListener)에 이벤트를 전달하며, 이때 튜토리얼 상태를 변경하여 이후 앱 오픈 시 튜토리얼이 아닌 LoggedOut RIB으로 라우팅 되도록 한다.
튜토리얼을 모두 마치면 위와 같은 로그인 화면이 나오게 된다.
다음 글에서는 로그인 및 회원가입을 위한 백앤드 삽질기를 공유해 보기로 하고 이번 글은 여기서 마친다.
'iOS' 카테고리의 다른 글
(iOS) Swift Macros 찍먹해보기 (0) | 2023.07.03 |
---|---|
(iOS) 유니플로거 리팩토링(3) 로그인, 회원가입 (feat. Spring Boot 삽질기) (5) | 2023.06.07 |
(iOS) 유니플로거 리팩토링(1) XCFramework (4) | 2023.05.07 |
(iOS) Library vs Framework(3) (0) | 2023.04.06 |
(iOS) Library vs Framework(2) (0) | 2023.03.07 |