화면 구성이 복잡하고 너무 많은 정보와 기능을 가지고 있는 View의 경우 view와 viewModel 각각 하나만 가지고 코드를 작성하기에 크기가 너무 커질 수 있다
-> 그래서 휴대폰에 보여지는 큰 뷰를 세분화 시킨 뒤 각각의 뷰가 뷰모델을 가질 수 있도록 프로젝트를 구성하였다
여러개의 View로 VC가 구성되다보니 결국 화면 전환을 할 때는 최상위 ViewModel을 통해 VC를 거쳐야하니 결국에는 최상위 ViewModel과 VC는 크기가 커질 수 밖에 없는 상황이 됐다...
그때 문득 떠오르는 생각이
“NavigationController의 최상위 뷰를 찾는 것 처럼 현재 화면에서 가장 상단에 있는 VC를 찾아주는 메서드도 있지 않을까?”
하고 찾아본 결과 기본으로 제공되는 메서드는 없고 아래 코드를 통해 가장 상단에 있는 VC를 반환해 줄 수 있다고 한다
코드를 먼저 보자면 아래와 같은데...
extension UIApplication {
static func topViewController(base: UIViewController? = UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}
솔직히... 코드만 보고 잘 이해가 되지 않아서 콘솔에 찍어 보면서 작동 과정을 확인해봤다.ㅋㅋ
먼저 topViewController
메서드에서는 총 세 가지를 체크한다
1. base
가 UINavigationController인지 (맞다면 NavigationController의 최상단 뷰를 base로 다시 topViewController 호출)
2. base
가 UITabBarController인지 (맞다면 TabBarController에서 선택된 뷰를 base로 다시 topViewController 호출)
3. base
가 present한 VC가 있는지 (있다면 해당 VC로 다시 topViewController 호출)
-> 이렇게 반복적으로 체크된 VC가 NavigationController도 아니고, TabBarController도 아니고 present한 VC가 없다면 최 상단에 띄워진 VC로 판단해 최종적으로 해당 VC를 반환하는 방식
(으로 이해했다… 맞겠쥬?)
마이 페이지의 뷰 계층을 보면 MainTabbarVC -> NavigationController -> MyPageVC이다
이 중 MainTabbarVC는 LunchScreenVC에서 present되는 VC이다
즉, 마이 페이지가 화면에 보이는 순서는 LunchScreenVC에서 MainTabbarVC를 present -> MainTabbarVC안의 NavigationController가 MyPageVC를 보여주는 순이다
그래서 MyPageVC의 세분화된 View에서 topViewController를 호출하면
topViewController를 처음 호출 했을 때 base에 들어가는 기본값, KeyWindow의 rootViewController이며
이 값은 LunchScreenVC이다
topViewController의 두 번째 호출은 1번의 keyWindow가 present한 MainTabbarVC를 base로 호출 된다
topViewController의 세 번째 호출은 2번의 MainTabbarVC에서 선택된 VC를 base로 호출 된다
(NavigationController생성시 따로 프로퍼티를 만들지 않아서 이름은 없지만 어쨌든 navigationController…)
topViewController의 네 번째 호출은 3번의 NavigationController의 맨 위에 보여지는 MyPageVC를 base로 호출된다
이렇게 해서 최종적으로 최상단에 떠있는 VC가 무었인지 알게 되었고 topViewController메서드를 통해 세분화된 뷰(UIView)에서도 다른 화면으로 화면전환을 할 수 있게 되었다
코드를 해석하는데도 머리가 아픈데 어떻게 이런 방법을 생각해내는건지 신기할 따름이다...
공식문서를 본 결과 topViewController는 가장 마지막스택에 있는 뷰(가장 마지막에 push된 뷰)이고 visibleViewController는 형식상 화면에 가장 맨 위에 있는 뷰라고 하는데 정상적으로 스택을 쌓지 않고 nvigation가장 위에 뷰가 올라 올 수 있어서 이걸 쓴건가?
(사실 어떻게 그런 경우가 발생할 수 있는지는 모르겠지만 이런 이유때문이라면 visibleViewController이 실제 화면에 보이는 뷰를 보여주기 적합할 수도 있겠다)
(여기서 말하는 topViewController는 위에 정의한 메서드가 아니라 UINavigationController의 메서드이다)