iOS 화면 판단

dev_will_d·2023년 4월 17일
1

개발을 하다보면 화면에 대한 정보를 알고 싶을때가 있다.

나는 이러한 정보를 아는 방법을 4가지로 분류해서 정리했다

  • RootViewController
    • 애플리케이션의 최상위 ViewController
  • TopMostViewController
    • 현재 화면에 보이는 ContainerViewController
  • DepthViewController
    • 현재 화면에 보이는 ChildViewController
  • ContainerType
    • 현재 화면의 Continer가 무엇인지 판단하는 Enum
  1. RootViewController
var rootViewController : UIViewController? {
        return (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController
}
  1. TopMostViewController
var topMostViewController: UIViewController? {
        guard let rootViewController = self.rootViewController else { return nil }

        var topMostViewController = rootViewController

        while let presentedViewController = topMostViewController.presentedViewController {
            topMostViewController = presentedViewController
        }

        while let parentViewController = topMostViewController.parent {
            if parentViewController is UINavigationController {
                topMostViewController = parentViewController
            } else if let presentedViewController = parentViewController.presentedViewController, presentedViewController != topMostViewController {
                topMostViewController = presentedViewController
            } else {
                break
            }
        }
        
        
        if topMostViewController.isViewLoaded && topMostViewController.view.window != nil {
            return topMostViewController
        } else {
            return nil
        }
    }

반복문을 통해서 최상의 ViewController 판단

  1. DepthViewController
var depthViewController : UIViewController? {
        get {
            var depthViewController = self.topMostViewController
            
            /*
             TabBar
             */
            if let tabBarController = depthViewController as? UITabBarController {
                depthViewController = tabBarController.selectedViewController
            }
            
            /*
             Navigation
             */
            if let navigationController = depthViewController as? UINavigationController {
                depthViewController = navigationController.visibleViewController
            }
            
            /*
             XLPager
             */
            if let pagerTapViewController = depthViewController as? ButtonBarPagerTabStripViewController {
                let currentIndex = pagerTapViewController.currentIndex
                depthViewController = pagerTapViewController.viewControllers[currentIndex]
            }
            
            
            if depthViewController?.isViewLoaded == true && depthViewController?.view.window != nil {
                return depthViewController
            } else {
                return nil
            }
        }
    }

최상의 ViewController의 타입을 판단해서 ChildeViewController 탐색

  1. ContainerType

enum VCContainerType {
case tabBar
case navigationBar
case pager
case vc
}

var containerType : VCContainerType? {
    get {
        guard let vc = self.topMostViewController else { return nil }
        if vc.isKind(of: UITabBarController.self) {
            return .tabBar
        } else if vc.isKind(of: UINavigationController.self) {
            return .navigationBar
        } else if vc.isKind(of: ButtonBarPagerTabStripViewController.self) {
            return .pager
        } else {
            return .vc
        }
    }
}

최상의 ViewController의 Container를 판단


위와 같이 코드를 작성하면 필요한 시점에서 ViewController의
정보를 얻을 수 있다. 이런식으로 ViewController의 정보를
얻으면 Model, Banner, LoadingView 표시할때 (ex Network 공통 예외처리)에서 효력을 발휘 할 수 있다.

ex) Modal

class CommonModal {
...
    func show() {
        if topMostViewController !== self {
            topMostViewController?.presentViewController(vc: self, modalTransitionStyle: .crossDissolve, modalPresentationStyle: .overFullScreen, backgroundColor: .clear)
        }
    }
}
...

ex) Network 공통 예외 처리 모달 표시

func commonAlert(
    uiMode : UIMode,
    title : String = "앱 오류",
    message : String
) {
    switch uiMode {
    case.NONE, .ONLY_LOADING:
        break
    case.ONLY_LOGIN, .ALERT_LOGIN:
        UserDefaults.standard.setValue("", forKey: "token")
        UserDefaults.standard.setValue(false, forKey: "isAutoLogin")
        UserDefaults.standard.setValue(0, forKey: "memberId")
        MessangerSocketIo.shared.sk_tlanslateBackground()
        
        let vc = ToryWebViewController()
        let viewmodel = ToryWebViewModel(path: .LOGIN)
        vc.bind(viewmodel)
        
        vc.view.backgroundColor = .togetherWhite
        vc.modalTransitionStyle = .crossDissolve
        vc.modalPresentationStyle = .fullScreen
        
        (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController = vc
        
    case.ONLY_WARNING, .ALERT_WARNING:
        WDModal.Builder()
            .setTitle(title)
            .setMessage(message)
            .setPositiveButton("확인") {
                $0.dismiss(animated: true)
            }
            .build()
            .show()
    case.ONLY_RESTART, .ALERT_RESTART:
        WDModal.Builder()
            .setTitle(title)
            .setMessage(message)
            .setPositiveButton("다시 시작하기") {
                $0.dismiss(animated: true)
                UIApplication.shared.perform(#selector(NSXPCConnection.suspend))
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                    exit(0)
                }
            }
            .build()
            .show()
    }
}
profile
질문의 질이 답의 질을 결정한다.

0개의 댓글