2. 뷰 전환은 어디에서 하는가
전글에서 다루는 Coordinator의 연장선입니다.
전글에서는 View와 Coordinator가 소통,화면 전환하는 법 그리고 Coordinator의 기본적이 구성에 대하여 글을 썻습니다.
그리고 말씀 드리는 와중에 Coordinator패턴에서는 객체를 잃지 않으려고 childCoordinator를 사용한다고 말했습니다.
이번에는 화면을 닫으면서 혹은 뒤로가면서 Coordinator가 이를 어떻게 감지하고 childCoordinator에서
삭제하는 지에 대하여 글을 써보겠습니다.
3. childCoordinator를 삭제 하는 법
우선 Coordinator를 쓰지 않을때는 어떻게 할까요?
그냥 self.navigationController?.popViewController() 혹은 self.dismiss() 함수를 활용하여 화면을 뒤로가게 됩니다.
과연 이렇게 함으로써 childCoordinator가 삭제 될까요? 한번 확인하고 가겠습니다.
보시는 바와 같이 MainCoordinator에서 화면 전환을 할때 childCoordinator의 갯수를 로그로 찍어보았습니다.
이때 그냥 popViewController를 하거나 dismiss()를 해도 MainCoordinator에서 childCoordinator가 삭제되지 않는 것을
확인할 수 있습니다.
왜냐하면 NavigationStack에서 사라지거나 ViewController가 dismiss해도 ParentCoordinator(MainCoordinator)가 이를 감지하지 못하기때문입니다.
따라서 이를 인지시키기 위해서 다음과 같은 방법들을 써야합니다.
3-1. (ViewController)Delegate를 사용하여 알리는 방법
가장 간단한 방법으로는 ViewController의 Delegate로 Coordinator에 화면 종료 시점을 알려주고
Coordinator가 ParentCoordinator로 자식을 삭제하라고 전달하는 것입니다.
일단 그러면 CoordinatorDelegate부터 작업을 해줍시다.
여기에서 === 을 쓴것은 swift에서 ===은 같은 instance를 참조하고 있는 것인지 비교 하는 것이기 때문입니다.
따라서 Coordinator2에서 parent.removeChildCoordinator(coordinator : self)이런식으로 함수를 호출해주게 되면
ParentCoordinator가 Coordinator2를 childCoordinator에서 삭제할 수 있는 것이죠.
그러면 이제 View의 Delegate들을 작업해줍시다.
이런식으로 ViewController에서 화면을 종료할때 Coordinator에게 "나 화면 종료했어! "라고 알려주는 것입니다.
그러면 Coordinator는 ParentCoordinator에게 "나 이제 할일 다했어 이제 없애줘"라고 알려줍니다.
이렇게 하면 다음과 같이 ChildCoordinator들이 삭제가 되는 것을 알 수 있습니다.
보시는 바와 같이 사용자가 만든 버튼으로 화면 종료 했을때는 childCoordiantor가 잘 삭제 되는 것을 알 수 있습니다.
하지만 기본 navigation BackBtn, 각종 Gesture로 화면 종료하는 것은 childCoordinator가 삭제 되지 않는 것을 알 수 있습니다.
따라서 이 방법을 사용하실려면 GestureRecognizer를 빼야하는 불상사가 생깁니다.
이건 그냥 반쪽짜리 솔루션인 것입니다.
그럼 어떻게 해야지 GestureRecognizer도 살리고 childCoordinator도 없앨 수 있을까요?
3-2. UINavigationControllerDelegate를 사용하는 방법 - (for NavigationStack)
우선 UINavigationTransitionDelegate를 사용하여 navigation pop의 상황을 탐지해보겠습니다.
바로 UINavigationControllerDelegate에서의
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) 함수를 사용하면 됩니다.
이렇게 하면 다른 push를 할때는 앞에 있던 ViewController가 pop할때는 맨뒤에 있던 ViewController가 fromViewController가 되게 됩니다.
간단하게 생각하면 fromViewController는 화면이 이동되기 전 마지막 ViewController를 말하는 것이라 생각하면 편할 것 같습니다.
따라서 fromViewController가 이미 navigationStack에 있다면 fromViewController가 다른 VC를 push하고 있다고 생각할 수 있습니다. 이때는 childCoordinator를 삭제하면 안되기 때문에 return 을 시키는 것입니다.
마지막으로 fromViewController가 현재 pop된 VC인지 확인하고 맞다면 childCoordinator를 삭제합니다.
이렇게 하면 별도로 ViewControllerDelegate로 Coordinator에게 알려줄 필요도 없고 더군다나 Gesture로 pop한 화면도 캐치됩니다.
한번 보시죠
childCoordinator가 잘 삭제되는 것을 볼 수 있습니다.
이렇게 하면 NavigationStack으로 전환된 화면들에 대해서는 해결된 것입니다.
그럼 이제 present, dismiss 가 남았습니다.
3-3. UIViewControllerTransitionDelegate를 사용하는 방법 - (for present, dismiss)
UInavigationDelegate와 같이 UIViewControllerTransitionDelegate을 사용하여 이벤트를 캐치하게 됩니다.
꽤나 명확한 함수가 존재합니다.
딱봐도 dismissed가 사라진 ViewController라는 것을 직감적으로 알 수 있습니다.
이제 PresentingViewController가 저함수를 사용할 수 있을려면 delegate를 채택해야겠죠?
이렇게 transitionDelegate를 채택해줍니다.
근데 여기서 전 처음 당연히 parent가 닫고 보여주고 관리해서 parent의 delegate를 가지고 채택하는 줄 알았는데
그게 아니라 view의 delegate에 연결을 해줘야 하더군요. 음 요건 왜 그런건지 모르겠네요.
그러고 나서 아까 navigation때와 같이 그냥 dismiss만 해줍니다.
이제 잘 작동하는지 확인해 보겠습니다.
역시나 잘 되네요.
이렇게 해서 ViewController의 Delegate가 아닌 UInavigationDelegate와 UIViewControllerTransitionDelegate을 사용하여
childCoordinator를 삭제하는 법을 알아보았습니다.
3-3. 마무리 간편하게
위와 같이 매 coordinator마다 델리게이트 작업을 해주게 되면 코드량도 많아지고 무엇보다 너무 귀찮습니다.
따라서 그냥 BaseCoordinator에 채택을 시켜줌으로써 코딩을 조금이나마 줄일 수 있습니다.
요런식으로 하면 이제 필요한 곳에서 함수만 override하여 써주시면 훨씬 더 간편하게 구현을 할수가 있습니다.
이번글에서는 간단한 상황에서의 ChildCoordinator삭제 방법에 대해서 알아보았습니다.
제가 "간단"하다고 말한 이유는 지금 하나의 Coordinator에서 여러개가 presenter되거나 여러개가 push되는 경우가 없기 때문이죠
예를 들어 뷰가 3개정도 push되었다고 생각해봅시다.
이때 위와 같이 하면 바로 coordinator가 없어지며 순서가 뒤죽박죽 되겠죠. 따라서 pop되는 ViewController가 Coordinator의 rootViewController인지 확인을 할 수 있어여 합니다.
그리고 마지막으로 MainCoordinator -> Coordinator2 -> Coordinator3 ... -> CoordinatorN의 경우 바로 MainCoordinator까지 pop하는 방식에 대해 다음글에 대해서 알아보겠습니다.
부족하지만 계속해서 읽고계시는 분들에게 감사합니다.
'iOS' 카테고리의 다른 글
MVVM(6) - ViewModel (0) | 2023.01.13 |
---|---|
MVVM(5) - Coordinator (0) | 2023.01.05 |
MVVM(3) - Coordinator (0) | 2022.12.23 |
MVVM (2) (0) | 2022.12.19 |
MVVM (1) - 바인딩 방법들 (1) | 2022.12.09 |