LoginSignup
53
43

More than 3 years have passed since last update.

[Swift 5]RootViewControllerを適用する備忘録

Last updated at Posted at 2019-08-10

例えば、初回起動時の利用規約確認ページの表示やウォークスルーの表示、またそれらの画面からメイン画面への移動について

AppDelegateを介してwindowrootViewControllerを切り替えたりしていたのですが、
メモリの関係であまり推奨されないらしい。

今回は専用のRootViewControllerを用意し、そのchildを挿げ替えるという方法があると知り、実践しました。
あわせて、起動時にはSplashViewControllerを用意して何らかのデータ取得や表示先画面の分岐を行っています。
今後Splash画面をアニメーションさせたくなったときにも入れやすそうです。

前提情報

個人的な好みですが、随所でViewControllerVCと略しています。

まずは肝心のRootViewControllerの作成

RootVC.swift
import UIKit

final class RootVC: UIViewController {
    // 現在表示しているViewControllerを示します
    private var current: UIViewController

    init() {
        // 起動時最初の画面はSplashViewControllerを設定します
        current = SplashVC()
        super.init(nibName: nil, bundle: nil)
    }
    // init()を実装したことによる必須実装
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // ViewControllerをRootVCの子VCとして追加
        addChild(current)
        current.view.frame = view.bounds
        view.addSubview(current.view)
        current.didMove(toParent: self)
    }

    /// RootVCの子VCを入れ替える=ルートの画面を切り替える
    func transition(to vc: UIViewController) {
        // 新しい子VCを追加
        addChild(vc)
        vc.view.frame = view.bounds
        view.addSubview(vc.view)
        vc.didMove(toParent: self)
        // 現在のVCを削除する準備
        current.willMove(toParent: nil)
        // Superviewから現在のViewを削除
        current.view.removeFromSuperview()
        // RootVCから現在のVCを削除
        current.removeFromParent()
        // 現在のVCを更新
        current = vc
    }
    // 移動したいViewControllerごとに用意しておくと簡単に使用できる
    func transitionToMain() {
        // 切り替えたい先のViewControllerを用意
        let vc = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()!
        transition(to: vc)
    }
}

AppDelegateで、最初に表示する画面をRootVCに設定する

AppDelegate.swift

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 以下を追加
        // 最初に表示させるViewControllerにRootVCを指定する
        window = UIWindow(frame: UIScreen.main.bounds)
        window!.rootViewController = RootVC()
        window!.makeKeyAndVisible()

        return true
    }

    // その他メソッド省略…
}

extension AppDelegate {

    /// AppDelegateのシングルトン
    static var shared: AppDelegate {
        return UIApplication.shared.delegate as! AppDelegate
    }
    /// rootViewControllerは常にRootVC
    var rootVC: RootVC {
        return window!.rootViewController as! RootVC
    }
}

SplashVC

SplashVC.swift
import UIKit
/// 起動時、LauchScreenの後に表示される最初の画面。起動処理や遷移先画面の分岐を行う
final class SplashVC: UIViewController {
    /// 処理中を示すインジケーター
    private lazy var activityIndicator: UIActivityIndicatorView = {
        let indicator = UIActivityIndicatorView(style: .whiteLarge)
        indicator.frame = view.bounds
        indicator.backgroundColor = UIColor(white: 0, alpha: 0.4)
        return indicator
    }()

    /// 処理中に表示させておくスプラッシュ画像。LaunchScreenでも同じ画像を指定しておく
    private lazy var splashImage: UIImageView = {
        let imageView = UIImageView(
            image: UIImage(named: "Japanese01")
        )
        imageView.contentMode = .scaleAspectFill
        imageView.frame = view.frame
        return imageView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(splashImage)
        view.addSubview(activityIndicator)
        // 起動時に行いたい処理を実行する
        // UsecaseなりPresenterなり・・
        activityIndicator.startAnimating()

        // 中略

        // メイン画面へ移動
        AppDelegate.shared.rootVC.transitionToMain()
    }
}

参考

53
43
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
53
43