Things take time

[SWIFT] 현재 실행 중(혹은 실행할) 앱의 최상 뷰 컨트롤러 얻기 본문

iOS (기능)

[SWIFT] 현재 실행 중(혹은 실행할) 앱의 최상 뷰 컨트롤러 얻기

겸손할 겸 2018. 2. 19. 13:17

[개요]


여러 개의 뷰 컨트롤러를 갖고 있는 앱에서, 그 계층 구조에 따라 동작함이 다르므로 이를 제어해야할 일이 생긴다.


예를 들어


1) 푸시 메시지를 클릭했을 때, A라는 뷰 컨틀로러 실행되어 있다면 특정 작업을 하고.. B라는 뷰 컨트롤러가 실행중이라면 B를 종료하고 A라는 컨트롤러를 제어해야 한다면


2) 스키마를 통해 앱을 들어온 경우에도 푸시 메시지를 클릭했을 때 처럼 각 뷰 컨트롤러 작업이 다르다면


이 때 필요한게 지금 현재 앱이 백그라운드에 있다가 켜졌을 때, 현재 실행중인 뷰 컨트롤러가 뭐냐는게 중요하다. (당연한 말이지만, 앱이 처음 켜진 경우엔 지금 현재 뷰 컨트롤러는 당연히 지정한 뷰 컨트롤러다)


[코드]


1. 현재의 뷰 컨트롤러 얻는 UIApplication의 Extension

extension UIApplication {
    class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.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
    }
}

이 코드를 사용하면, 어디서나 UIApplication.topViewController()를 통해 현재 뷰 컨트롤러를 접근할 수 있다.


2. 탭바나 네비게이션 컨트롤러 없다면

            let rootVC =   UIApplication.shared.keyWindow?.rootViewController
            let presentVC = rootVC?.presentedViewController
            
            if presentVC != nil{
                if let contentVC = presentVC as? ContentViewController{
                    contentVC.quitView(url: urlStr)
                }
            } else{
                let mainVC = rootVC as! MainViewController
                mainVC.webView.load(request)
            }

기본적으로 rootViewController를 통해 현재 앱의 가장 밑 부분에 있는 컨트롤러.. 즉 앱을 켰을 때 처음 실행되는 뷰 컨트롤러를 얻을 수 있고 presentedViewController를 통해 그 위에 얹어져 있는 가장 상단의 뷰 컨트롤러를 얻을 수 있다.


만약, presentVC가 nil이라면, 현재 띄워져 있는 뷰 컨트롤러는 루트 뷰 컨트롤러를 의미하는 것이고, 있다면 얹어진 뷰 컨트롤러를 if let 구문을 통해 찾아낸 다음 원하는 작업을 수행하면 된다.