警告:ビューがウィンドウ階層にない*に*を表示しようとしています-迅速


83

データモデルに保存されたデータがあるかViewController どうかを提示しようとしています。しかし、次のエラーが発生します。

警告:ビューがウィンドウ階層にない*に*を表示しようとしています。 "

関連コード:

override func viewDidLoad() {
    super.viewDidLoad()
    loginButton.backgroundColor = UIColor.orangeColor()

    var request = NSFetchRequest(entityName: "UserData")
    request.returnsObjectsAsFaults = false

    var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
    var context:NSManagedObjectContext = appDel.managedObjectContext!

    var results:NSArray = context.executeFetchRequest(request, error: nil)!

    if(results.count <= 0){
        print("Inga resultat")
    } else {
        print("SWITCH VIEW PLOX")
        let internVC = self.storyboard?.instantiateViewControllerWithIdentifier("internVC") as internViewController
        self.presentViewController(internVC, animated: true, completion: nil)
    }
}

Googleを使用して見つかったさまざまなソリューションを試しましたが成功しませんでした。


ストーリーボードでViewControllerを接続しましたか?ここでNavigationControllerを使用していますか?
derdida 2014

ViewControllerストーリーボードで接続した場合はどういう意味ですか?私はNavigationController@derdidaを使用していません
Nils Wasell 2014

試してみてください:ViewDidLoadのself.addChildViewController(childController:UIViewController)
derdida

これによりエラーが発生します。「タイプ名」(UIViewControllerパーツ)の後にメンバー名またはコンストラクター呼び出しが必要です。@derdida
Nils Wasell 2014

どこに書いたの?MainViewControllerのViewDidLoadで?
derdida 2014

回答:


126

コードのこの時点では、View Controllerのビューは作成されているだけで、ビュー階層には追加されていません。そのViewControllerからできるだけ早く提示したい場合はviewDidAppear、最も安全にするためにそれを行う必要があります。


2
それをviewDidAppearに配置すると、presentedViewControllerを閉じると、viewDidAppearメソッドが再度呼び出され、viewControllerが再度表示されます。表示する前に条件ステートメントを配置する回避策がありますが、条件文?
プニット2014年

2
画面が表示されたときに別のモーダル権利を提示しようとするのは、そもそも奇妙な動作であるため、状態ブールが最悪の解決策になることはほとんどありません。同時に、モーダルを表示する必要がある根本的な理由を考えて、その情報にアクセスできるかどうかを確認してください。
acey 2014年

2
viewWillAppearで行うと、プレゼンテーションを開始したときにプレゼンテーションの途中になっている状況になります。別の方法は、それをviewWillAppearに配置することですが、iOS 8の新しいtransitionCoordinatorプロパティを使用して、遷移の完了時にコードを追加します。詳細については、developer.apple.com
library / prerelease / ios / documentation / UIKit /…を

36

目的c:これはmpmovieplayerの上にviewcontrollerを提示するときの私の問題を解決しました

- (UIViewController*) topMostController
{
    UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

    while (topController.presentedViewController) {
        topController = topController.presentedViewController;
    }

    return topController;
}

34

スウィフト3

私はこれを初心者として取り上げ続けましたが、現在は却下できるモーダルビューをロードしますが、モーダルを表示する必要がない場合はルートコントローラーに切り替えるのが最適です。

私はこれを使っていました

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc  = storyboard?.instantiateViewController(withIdentifier: "MainAppStoryboard") as! TabbarController
present(vc, animated: false, completion: nil)

代わりにこれをtabControllerで使用します。

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let view = storyboard.instantiateViewController(withIdentifier: "MainAppStoryboard") as UIViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//show window
appDelegate.window?.rootViewController = view

複数のストーリーボード画面を切り替える必要がある場合は、ViewControllerに調整するだけです。


16

スウィフト3。

この関数を呼び出して最上位のViewControllerを取得し、そのViewControllerを存在させます。

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
        while (topController.presentedViewController != nil) {
            topController = topController.presentedViewController!
        }
        return topController
    }

使用法:

let topVC = topMostController()
let vcToPresent = self.storyboard!.instantiateViewController(withIdentifier: "YourVCStoryboardID") as! YourViewController
topVC.present(vcToPresent, animated: true, completion: nil)

1
これについては@JacobDavisに感謝します!私は私が警告を得ていた原因alertControllerを提示するためにそれを使用して本にしようとしました....
ゲイリーMansted

これはとても便利です。いくつかのコントローラーを提示していますが、画面が表示されていません。突然それは却下されます。他のコードを実装する必要がありますか?提案してください
Seethalakshmi_user8943692

13

SWIFT用

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}

1
ありがとうございました!これが私にとってこのエラーを解決した唯一のことでした。ビューが完全にロードされた後(Xcode 8 / iOS 10)、ジェスチャレコグナイザーによってトリガーされた関数からモーダルVCを提示しようとしていました。不思議なことに、topControllerこの関数によって返されるのは、selfを使用して直接提示しようとした場合とまったく同じVCですが、関数を使用self.presentViewController(myModalVC)して提示VCを渡してもビュー階層エラーはありません。
ナタリア2016

13

セレクターを遅らせて実行する必要があります-(0秒で動作します)。

override func viewDidLoad() {
    super.viewDidLoad()
    perform(#selector(presentExampleController), with: nil, afterDelay: 0)
}

@objc private func presentExampleController() {
    let exampleStoryboard = UIStoryboard(named: "example", bundle: nil)
    let exampleVC = storyboard.instantiateViewController(withIdentifier: "ExampleVC") as! ExampleVC
    present(exampleVC, animated: true) 
}

どうもありがとう。私はこの問題で1時間以上立ち往生しました。
reza 2016

ありがとう... @ objc func presentExampleController()
William Choy

素晴らしい答えだと思います!
mazend

これはハックです(現在は機能する可能性があります)が、予期しない場合に機能しなくなる可能性があります。
ウィリアムグランド

6

スウィフト4

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}

1
説明と例が役に立つ@AllenWixtedだろう
エウリー・ペレスBeltré

2

swift3.0以降の場合

public static func getTopViewController() -> UIViewController?{
if var topController = UIApplication.shared.keyWindow?.rootViewController
{
  while (topController.presentedViewController != nil)
  {
    topController = topController.presentedViewController!
  }
  return topController
}
return nil}

2

ユーザーがディープリンクを開いた後、コントローラーを提示しているときにこのエラーが発生していました。これが最善の解決策ではないことはわかっていますが、時間枠が短い場合は、ここで簡単に修正できます。コードをasyncAfter次のようにラップするだけです。

DispatchQueue.main.asyncAfter(deadline: .now() + 0.7, execute: { [weak self] in
                                navigationController.present(signInCoordinator.baseController, animated: animated, completion: completion)
                            })

提示するコントローラーがを呼び出すための時間が与えられますviewDidAppear


1
let storyboard = UIStoryboard(name: "test", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "teststoryboard") as UIViewController
UIApplication.shared.keyWindow?.rootViewController?.present(vc, animated: true, completion: nil)

これは、それが一番上のビューであることを確認するために機能しているように見えました。

エラーが発生していました

警告:ビューがウィンドウ階層にないmyapp.testController:0x7fdd01703690にmyapp.testController:0x7fdd01703990を表示しようとしています!

これが他の人の迅速な3に役立つことを願っています


1

私はたくさんのアプローチを試しました!唯一の便利なことは次のとおりです。

if var topController = UIApplication.shared.keyWindow?.rootViewController
{
  while (topController.presentedViewController != nil)
  {
    topController = topController.presentedViewController!
  }
}

1

ここでのtopViewControllerのすべての実装は、UINavigationControllerまたはがある場合を完全にサポートしているわけではありません。UITabBarControllerこれら2つの場合、少し異なる処理が必要です。

以下のためにUITabBarControllerUINavigationController、あなたは別の実装を必要としています。

topMostViewControllerを取得するために使用しているコードは次のとおりです。

protocol TopUIViewController {
    func topUIViewController() -> UIViewController?
}

extension UIWindow : TopUIViewController {
    func topUIViewController() -> UIViewController? {
        if let rootViewController = self.rootViewController {
            return self.recursiveTopUIViewController(from: rootViewController)
        }

        return nil
    }

    private func recursiveTopUIViewController(from: UIViewController?) -> UIViewController? {
        if let topVC = from?.topUIViewController() { return recursiveTopUIViewController(from: topVC) ?? from }
        return from
    }
}

extension UIViewController : TopUIViewController {
    @objc open func topUIViewController() -> UIViewController? {
        return self.presentedViewController
    }
}

extension UINavigationController {
    override open func topUIViewController() -> UIViewController? {
        return self.visibleViewController
    }
}

extension UITabBarController {
    override open func topUIViewController() -> UIViewController? {
        return self.selectedViewController ?? presentedViewController
    }
}

1

Swiftメソッド、およびデモを提供します。

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}

func demo() {
    let vc = ViewController()
    let nav = UINavigationController.init(rootViewController: vc)
    topMostController().present(nav, animated: true, completion: nil)
}

1

ビューコントローラを表示および閉じるためのメインスレッドの使用は私のために働いた。

DispatchQueue.main.async { self.present(viewController, animated: true, completion: nil) }

0

トップビューコントローラーを見つけるのではなく、

viewController.modalPresentationStyle = UIModalPresentationStyle.currentContext

viewControllerが表示するコントローラーである場合これは、TabBar、NavBarなどの階層にさまざまな種類のビューがある場合に役立ちますが、他のビューは正しいように見えますが、よりハックなものです。

他のプレゼンテーションスタイルはアップルドキュメントで見つけることができます


0

前の回答は、ビューを表示する必要があるビューコントローラが1)ビュー階層にまだ追加されていない、または2)最上位のビューコントローラではない状況に関連しています。
別の可能性は、別のアラートがすでに表示されていて、まだ却下されていないときにアラートを表示する必要があることです。


0

Swift 5.1

let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
let mainViewController = storyboard.instantiateViewController(withIdentifier: "ID")
let appDeleg = UIApplication.shared.delegate as! AppDelegate
let root = appDeleg.window?.rootViewController as! UINavigationController
root.pushViewController(mainViewController, animated: true)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.