[iOS] RootViewController를 구현하여 화면을 전환해 보았습니다.
소개
로그인/로그아웃에 의해 화면을 전환하고 싶은 상황은 자주 있다고 생각합니다.
UIWindow의 rootViewController를 바꾸어 앱 어디서나 화면을 전환할 수 있도록 해 보았습니다.
아래 GIF 이미지와 같이 앱의 화면 전환을 구현합니다.
 
 환경
[Xcode] 버전 12.4
[Swift] 버전 5.3.2
[iOS] 14.4
[MacOS] 10.15.7
 구현 절차
[Xcode] 버전 12.4
[Swift] 버전 5.3.2
[iOS] 14.4
[MacOS] 10.15.7
구현 절차
rootViewController를 직접 전환하는 것은 그다지 권장되지 않는 것 같습니다. rootViewController의 하위 ViewController를 전환하고 rootViewController를
RootViewController로 항상 설정합니다.이유는 메모리의 관계로, , 라고 하는 기사를 보았던 적이 있습니다만, 나 자신이 그 내용을 제대로 이해하고 있지 않기 때문에, 어디까지나 화면을 전환하는 1 수법으로서 도입하고 싶습니다.
SplashViewController)을 만들고 전환 대상 화면을 전환합니다.여기의 내용은 생략합니다.
이 앱에는 SceneDelegate가 필요하지 않으므로 SceneDelegate를 삭제하고 AppDelegate를 통해 Window의 rootViewController를 가져옵니다. iOS13 이상에서 SceneDelegate를 사용하지 않고 AppDelegate를 사용하는 방법에 대한 설명은 이 기사에서는 생략합니다.
이 기사 가 알기 쉬웠으므로 참고로 했습니다.
RootViewController
RootViewControllerimport UIKit
final class RootViewController: UIViewController {
    //現在のアプリケーションの状態を追跡するために、現在のViewControllerを指す変数を作成
    private var current = UIViewController()
    override func viewDidLoad() {
        super.viewDidLoad()
        //viewをロードするとすぐに呼ばれるSplashViewControllerを準備する
        current = SplashViewController()     
        addChild(current)
        current.view.frame = view.bounds
        view.addSubview(current.view)
        current.didMove(toParent: self)  
    }
    //メイン画面への遷移メソッド
    func switchToMainScreen() {
        let mainViewController = MainViewController()
        let new = UINavigationController(rootViewController: mainViewController)
        animateFadeTransition(to: new)
    }
    //ログイン画面へ遷移するメソッド
    func switchToLogin() { 
        let loginViewController = LoginViewController()
        let new = UINavigationController(rootViewController: loginViewController)
        animateFadeTransition(to: new) 
    }
    //メイン画面に遷移する際のアニメーションメソッド
    private func animateFadeTransition(to new: UIViewController, completion: (() -> Void)? = nil) {
        current.willMove(toParent: nil)
        addChild(new)
        //ページ遷移
        transition(from: current, to: new, duration: 0.3, options: [.transitionCrossDissolve, .curveEaseOut], animations: {}) { (completed) in
            self.current.removeFromParent()
            new.didMove(toParent: self)
            self.current = new
            //完了
            completion?()  
        }
    }
  //上記遷移メソッドの中身の各コードを説明 (showLoginScreen()というメソッドがあると仮定します)
    func showLoginScreen() {
        //遷移先のViewControllerオブジェクトを作成
        let loginViewController = LoginViewController()
        let new = UINavigationController(rootViewController: loginViewController)
        //それをRootViewControllerの子ViewControllerとして追加
        addChild(new)
        //Viewのフレームを位置合わせ
        new.view.frame = view.bounds
        //そのビューをaddSubView
        view.addSubview(new.view)
        //新しいViewControllerを追加した直後に呼び出す必要あり
        new.didMove(toParent: self)
        //willMoveを呼び出して、現在の子ViewControllerを削除する準備
        current.willMove(toParent: nil)
        //現在のビューをスーパービューから削除
        current.view.removeFromSuperview()
        //現在の子ViewControllerを親のRootViewController切り離す
        current.removeFromParent()
        //最後に現在の子viewControllerを更新することを忘れずに。
        current = new
    }
 SplashViewController
SplashViewController
import UIKit
//ユーザーの状況によって、アプリ起動後の遷移先を切り替える
final class SplashViewController: UIViewController {
    //処理進行を示すインジケータ
    private lazy var activityIndicator: UIActivityIndicatorView = {
        let activityIndicator = UIActivityIndicatorView(style: .large)
        activityIndicator.frame = view.bounds
        activityIndicator.color = .white
        activityIndicator.backgroundColor = UIColor(white: 0.5, alpha: 0.4)
        return activityIndicator
    }()
    override func viewDidLoad() {
        super.viewDidLoad()   
        view.backgroundColor = .white
        view.addSubview(activityIndicator)
        //アプリ起動時の画面切り替え
        makeScreenTransition()
    }
    //ユーザーの状態によって画面を切り替えるメソッド
    private func makeScreenTransition() {
        //1秒後に止まる遅延処理
        activityIndicator.startAnimating()
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(1)) {
            self.activityIndicator.stopAnimating()
            //今回はログイン状況をデバイスに保存している想定です
            if UserDefaults.standard.bool(forKey: "isLogin") {
                //メイン画面へ
                AppDelegate.shared.rootViewController.switchToMainScreen()
            } else {
                //ログイン画面へ
                AppDelegate.shared.rootViewController.switchToLogin()
            }   
        }  
    }
}
 AppDelegate
AppDelegate 싱글 톤을 만들어 어디서나 호출하여 화면을 전환 할 수 있습니다.
AppDelegateimport UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {       
        let window = UIWindow(frame: UIScreen.main.bounds)
        self.window = window
        //RootViewControllerを設定
        window.rootViewController = RootViewController()
        window.makeKeyAndVisible()
        return true
    }
}
extension AppDelegate {
    //シングルトン
    static var shared: AppDelegate {
        return UIApplication.shared.delegate as! AppDelegate
    }
    var rootViewController: RootViewController {
        return window!.rootViewController as! RootViewController
    }
}
 마지막으로
RootViewController가 화면 전환을 담당하기 때문에 저처럼 단순한 디자인의 앱을 개발하고 있는 경우에는 구현, 관리의 쉬운 방법이라고 생각했습니다.
앞으로 더 복잡한 상황에 대한 대응과 더 나은 구현 방법이 있다면 배우고 기사로 갈 수 있다고 생각합니다.
 참고문헌
이 기사는 다음 정보를 참고했습니다.
- iOS: Root Controller Navigation
- iOS13에서 SceneDelegate를 사용하지 않고 앱 만들기
                
                    
        
    
    
    
    
    
                
                
                
                
                    
                        
                            
                            
                            Reference
                            
                            이 문제에 관하여([iOS] RootViewController를 구현하여 화면을 전환해 보았습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
                                
                                https://qiita.com/mtkmr/items/6840fc5c1ac342a55055
                            
                            
                            
                                텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                            
                            
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)
                            
                            
                        
                    
                
                
                
            
import UIKit
final class RootViewController: UIViewController {
    //現在のアプリケーションの状態を追跡するために、現在のViewControllerを指す変数を作成
    private var current = UIViewController()
    override func viewDidLoad() {
        super.viewDidLoad()
        //viewをロードするとすぐに呼ばれるSplashViewControllerを準備する
        current = SplashViewController()     
        addChild(current)
        current.view.frame = view.bounds
        view.addSubview(current.view)
        current.didMove(toParent: self)  
    }
    //メイン画面への遷移メソッド
    func switchToMainScreen() {
        let mainViewController = MainViewController()
        let new = UINavigationController(rootViewController: mainViewController)
        animateFadeTransition(to: new)
    }
    //ログイン画面へ遷移するメソッド
    func switchToLogin() { 
        let loginViewController = LoginViewController()
        let new = UINavigationController(rootViewController: loginViewController)
        animateFadeTransition(to: new) 
    }
    //メイン画面に遷移する際のアニメーションメソッド
    private func animateFadeTransition(to new: UIViewController, completion: (() -> Void)? = nil) {
        current.willMove(toParent: nil)
        addChild(new)
        //ページ遷移
        transition(from: current, to: new, duration: 0.3, options: [.transitionCrossDissolve, .curveEaseOut], animations: {}) { (completed) in
            self.current.removeFromParent()
            new.didMove(toParent: self)
            self.current = new
            //完了
            completion?()  
        }
    }
  //上記遷移メソッドの中身の各コードを説明 (showLoginScreen()というメソッドがあると仮定します)
    func showLoginScreen() {
        //遷移先のViewControllerオブジェクトを作成
        let loginViewController = LoginViewController()
        let new = UINavigationController(rootViewController: loginViewController)
        //それをRootViewControllerの子ViewControllerとして追加
        addChild(new)
        //Viewのフレームを位置合わせ
        new.view.frame = view.bounds
        //そのビューをaddSubView
        view.addSubview(new.view)
        //新しいViewControllerを追加した直後に呼び出す必要あり
        new.didMove(toParent: self)
        //willMoveを呼び出して、現在の子ViewControllerを削除する準備
        current.willMove(toParent: nil)
        //現在のビューをスーパービューから削除
        current.view.removeFromSuperview()
        //現在の子ViewControllerを親のRootViewController切り離す
        current.removeFromParent()
        //最後に現在の子viewControllerを更新することを忘れずに。
        current = new
    }
SplashViewController
import UIKit
//ユーザーの状況によって、アプリ起動後の遷移先を切り替える
final class SplashViewController: UIViewController {
    //処理進行を示すインジケータ
    private lazy var activityIndicator: UIActivityIndicatorView = {
        let activityIndicator = UIActivityIndicatorView(style: .large)
        activityIndicator.frame = view.bounds
        activityIndicator.color = .white
        activityIndicator.backgroundColor = UIColor(white: 0.5, alpha: 0.4)
        return activityIndicator
    }()
    override func viewDidLoad() {
        super.viewDidLoad()   
        view.backgroundColor = .white
        view.addSubview(activityIndicator)
        //アプリ起動時の画面切り替え
        makeScreenTransition()
    }
    //ユーザーの状態によって画面を切り替えるメソッド
    private func makeScreenTransition() {
        //1秒後に止まる遅延処理
        activityIndicator.startAnimating()
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(1)) {
            self.activityIndicator.stopAnimating()
            //今回はログイン状況をデバイスに保存している想定です
            if UserDefaults.standard.bool(forKey: "isLogin") {
                //メイン画面へ
                AppDelegate.shared.rootViewController.switchToMainScreen()
            } else {
                //ログイン画面へ
                AppDelegate.shared.rootViewController.switchToLogin()
            }   
        }  
    }
}
AppDelegate
AppDelegate 싱글 톤을 만들어 어디서나 호출하여 화면을 전환 할 수 있습니다.
AppDelegateimport UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {       
        let window = UIWindow(frame: UIScreen.main.bounds)
        self.window = window
        //RootViewControllerを設定
        window.rootViewController = RootViewController()
        window.makeKeyAndVisible()
        return true
    }
}
extension AppDelegate {
    //シングルトン
    static var shared: AppDelegate {
        return UIApplication.shared.delegate as! AppDelegate
    }
    var rootViewController: RootViewController {
        return window!.rootViewController as! RootViewController
    }
}
 마지막으로
RootViewController가 화면 전환을 담당하기 때문에 저처럼 단순한 디자인의 앱을 개발하고 있는 경우에는 구현, 관리의 쉬운 방법이라고 생각했습니다.
앞으로 더 복잡한 상황에 대한 대응과 더 나은 구현 방법이 있다면 배우고 기사로 갈 수 있다고 생각합니다.
 참고문헌
이 기사는 다음 정보를 참고했습니다.
- iOS: Root Controller Navigation
- iOS13에서 SceneDelegate를 사용하지 않고 앱 만들기
                
                    
        
    
    
    
    
    
                
                
                
                
                    
                        
                            
                            
                            Reference
                            
                            이 문제에 관하여([iOS] RootViewController를 구현하여 화면을 전환해 보았습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
                                
                                https://qiita.com/mtkmr/items/6840fc5c1ac342a55055
                            
                            
                            
                                텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                            
                            
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)
                            
                            
                        
                    
                
                
                
            
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {       
        let window = UIWindow(frame: UIScreen.main.bounds)
        self.window = window
        //RootViewControllerを設定
        window.rootViewController = RootViewController()
        window.makeKeyAndVisible()
        return true
    }
}
extension AppDelegate {
    //シングルトン
    static var shared: AppDelegate {
        return UIApplication.shared.delegate as! AppDelegate
    }
    var rootViewController: RootViewController {
        return window!.rootViewController as! RootViewController
    }
}
RootViewController가 화면 전환을 담당하기 때문에 저처럼 단순한 디자인의 앱을 개발하고 있는 경우에는 구현, 관리의 쉬운 방법이라고 생각했습니다.
앞으로 더 복잡한 상황에 대한 대응과 더 나은 구현 방법이 있다면 배우고 기사로 갈 수 있다고 생각합니다.
참고문헌
이 기사는 다음 정보를 참고했습니다.
- iOS: Root Controller Navigation
- iOS13에서 SceneDelegate를 사용하지 않고 앱 만들기
                
                    
        
    
    
    
    
    
                
                
                
                
                    
                        
                            
                            
                            Reference
                            
                            이 문제에 관하여([iOS] RootViewController를 구현하여 화면을 전환해 보았습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
                                
                                https://qiita.com/mtkmr/items/6840fc5c1ac342a55055
                            
                            
                            
                                텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                            
                            
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)
                            
                            
                        
                    
                
                
                
            
Reference
이 문제에 관하여([iOS] RootViewController를 구현하여 화면을 전환해 보았습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/mtkmr/items/6840fc5c1ac342a55055텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)