Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

AppDelegateから一番上のUIViewControllerにアクセスする方法

More than 1 year has passed since last update.

AppDelegateからUI操作を行う時、UIViewControllerが複数重なっている時は一番上(最前面)のUIViewControllerにアクセスする必要がありますよね。
今回はその方法について調べてみました。

準備

以下の様な3つのUIViewControllerをSegueで順に起動するサンプルプログラムを作成します。
AppDelegate.png
青いUIViewControllerにはFirstViewController、黄色いUIViewControllerにはSecondViewController、赤いUIViewControllerにはThirdViewControllerというクラス名をつけておきます。

処理

今回はAppDelegateのapplicationWillEnterForegroundに処理を記述しました。
ホームボタンやホームインジケータを押下してアプリを一度バックグラウンドにして、その後フォアグラウンドに復帰させた時に走るイベントです。

AppDelegate.swift
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

-------------------- (中略) --------------------
    func applicationWillEnterForeground(_ application: UIApplication) {
        //一番手前のViewControllerを取得
        var viewController = UIApplication.shared.keyWindow?.rootViewController

        //PresentedViewControllerが取得できなくなるまでループ
        while viewController!.presentedViewController != nil {

            let presentedViewController = viewController!.presentedViewController

            //UIAlertControllerは対象外とする
            if let alertController = presentedViewController as? UIAlertController {
                //一番上がUIAlertControllerであればUIAlertControllerを閉じる
                alertController.dismiss(animated: true, completion: nil)
                break
            } else {
                //UIAlertControllerでなければ取得
                viewController = presentedViewController
            }
        }

        var message: String = ""

        if viewController is FirstViewController {
            message = "1番目のViewControllerです"
        }

        if viewController is SecondViewController {
            message = "2番目のViewControllerです"
        }

        if viewController is ThirdViewController {
            message = "3番目のViewControllerです"
        }

        let alertController: UIAlertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
        let defaultAction: UIAlertAction = UIAlertAction(title: "OK", style: .default, handler: nil)
        alertController.addAction(defaultAction)
        viewController!.present(alertController, animated: true, completion: nil)
    }
}

一番上のUIViewControllerを取得して、そこからアラートを表示する処理を記述しています。

サンプルプログラムを動かすとフォアグラウンドになった時に現在表示している画面をアラートで表示します。
ezgif-4-4554282cb2d2.gif

解説

まずUIApplicationからrootViewController(一番手前のUIViewController)を取得します。

var viewController = UIApplication.shared.keyWindow?.rootViewController

そしてrootViewControllerからpresentedViewControllerをループして取得します。

while viewController!.presentedViewController != nil {
    let presentedViewController = viewController!.presentedViewController

一番最後に返ってきたpresentedViewControllerが一番上のUIViewControllerになるのですが、ここで1点注意が必要です。
アラートを表示するUIAlertControllerや、App Extensionsを表示するUIActivityViewControllerもUIViewControllerを継承しているので、presentedViewControllerで返ってきます。
その為、一番上がUIAlertControllerやUIActiveViewControllerであった場合はその一つ手前のUIViewControllerが一番上のUIViewControllerになります。
今回のサンプルでもUIAlertControllerが表示されている可能性はあるので、UIAlertControllerだったらそれを閉じて、その一つ手前のUIViewControllerを一番上のUIViewControllerとして取得するようにしています。

while viewController!.presentedViewController != nil {

    let presentedViewController = viewController!.presentedViewController

    //UIAlertControllerは対象外とする
    if let alertController = presentedViewController as? UIAlertController {
       //一番上がUIAlertControllerであればUIAlertControllerを閉じる
       alertController.dismiss(animated: true, completion: nil)
       break
    } else {
       //UIAlertControllerでなければ取得
       viewController = presentedViewController
    }
}

どのUIViewControllerが一番上に来ているのかは「is」を使用してクラス名と型比較をすればわかります。

var message: String = ""

if viewController is FirstViewController {
   message = "1番目のViewControllerです"
}

if viewController is SecondViewController {
   message = "2番目のViewControllerです"
}

if viewController is ThirdViewController {
   message = "3番目のViewControllerです"
}
NaoSekig
Studio K's オーナープログラマー。 自社アプリ開発と請負開発の二足のわらじで奮闘中です(^o^)。
https://www.studioks.net/jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away