プッシュされたコントローラーからRootViewControllerを取得するにはどうすればよいですか?


137

だから、私はRootViewControllerからビューコントローラーを次のようにプッシュします:

[self.navigationController pushViewController:anotherViewController animated:YES];

しかし、anotherViewController今から、再びRootViewControllerにアクセスしたいと思います。

私はしようとしています

//(今度はanotherViewController内)
/// RootViewController * root =(RootViewController *)self.parentViewController; // 番号。
//エラー
RootViewController * root =(RootViewController *)[self.navigationController.viewControllers objectAtIndex:0]; // はい!!できます

なぜこれが機能するのか、またそれが最善の方法であるのかどうかはわかりません。誰かがRootViewControllerのnavigationControllerにプッシュしたコントローラーからRootViewControllerを取得するためのより良い方法や、私が行った方法が信頼できるかどうかについてコメントできますか?


あなたがやったことは確実にルートビューコントローラー(ナビゲーション階層の最初のもの)を取得します、もし「バック」ビューコントローラーへのアクセスを取得したいのであれば、私の答えを見てください。
ベンS

回答:


133

UINavigationControllerのviewControllersプロパティを使用します。コード例:

// Inside another ViewController
NSArray *viewControllers = self.navigationController.viewControllers;
UIViewController *rootViewController = [viewControllers objectAtIndex:viewControllers.count - 2];

これは、「バック」ビューコントローラを取得する標準的な方法です。機能する理由objectAtIndex:0は、アクセスしようとしているビューコントローラーがルートコントローラーでもあるためです。ナビゲーションの奥にいる場合、背面ビューはルートビューと同じではありません。


6
:) ty。まだハッキリしているようです
:) self.navigationController.rootViewControllerの

62
上記のコードは誤りです。rootViewControllerその*前に欠落しており、インデックスはちょうどです0。問題のコードは正しいです:RootViewController *root = (RootViewController *)[navigationController.viewControllers objectAtIndex:0]
ma11hew28

2
同意:上記のコードは、OPが要求したルートビューコントローラーではなく、ビューコントローラーを返します。それでも、ベンSはそうするつもりだと彼は言った。彼はそれを十分に指摘しなかった。
IvanVučica11年

2行目は次のようになります。UIViewController * rootViewController = [viewControllers objectAtIndex:viewControllers.count-1];
ビリー

177

Swiftバージョン:

var rootViewController = self.navigationController?.viewControllers.first

ObjectiveCバージョン:

UIViewController *rootViewController = [self.navigationController.viewControllers firstObject];

ここで、selfは、UINavigationControllerに埋め込まれたUIViewControllerのインスタンスです。


別のクラスから別のViewControllerのnavigationControllerを取得できますか?
sasquatch

すべてのUIViewControllerサブクラスには、NINavigationControllerクラスに一致する最初のparentViewControllerを指すnavigationControllerプロパティがあります。
ダルガン

12

これらのほとんどすべての回答で言及されている同じことの少し醜いバージョン:

UIViewController *rootViewController = [[self.navigationController viewControllers] firstObject];

あなたの場合、私はおそらく次のようなことをします:

UINavigationControllerサブクラス内

- (UIViewController *)rootViewController
{
    return [[self viewControllers] firstObject];
}

それからあなたは使うことができます:

UIViewController *rootViewController = [self.navigationController rootViewController];

編集する

OPはコメントでプロパティを要求しました。

必要に応じself.navigationController.rootViewControllerて、ヘッダーにreadonlyプロパティを追加するだけでアクセスできます。

@property (nonatomic, readonly, weak) UIViewController *rootViewController;

8

迅速な拡張に興味があるすべての人にとって、これは私が現在使用しているものです:

extension UINavigationController {
    var rootViewController : UIViewController? {
        return self.viewControllers.first
    }
}

1
ありがとう!また、「as?UIViewController」を削除することもできます
atereshkov

3

@dulganの回答への追加として、配列にオブジェクトがない場合は最初にnilを返しますが、後者は例外をスローするため、これは常にfirstObjectover を使用する良いアプローチobjectAtIndex:0です。

UIViewController *rootViewController = self.navigationController.rootViewController;

または、名前の付いたカテゴリを作成し、UINavigationController+Additionsその中でメソッドを定義することは大きなプラスになります。

@interface UINavigationController (Additions)

- (UIViewController *)rootViewController;

@end

@implementation UINavigationController (Additions)

- (UIViewController *)rootViewController
{
    return self.viewControllers.firstObject;
}

@end

私はあなたの答えを読まずにこの部分を追加しました、あなたは完全に正しいです "firstObject"はより良い[0]
dulgan

1

どのように尋ねる程度のUIApplication シングルトンをそのためkeyWindow、それからUIWindowは、ルートビューコントローラ(そのために頼むrootViewControllerのプロパティ):

UIViewController root = [[[UIApplication sharedApplication] keyWindow] rootViewController];

ナビゲーションコントローラーの入手方法
Yestay Muratov

これは、アプリケーションのrootviewcontrollerがUITabBarViewControllerである場合はどうなるのか、間違った提案です。
Sandeep Singh Rana

1

ここで私は、あらゆる場所からルートに移動するための普遍的な方法を思いつきました。

  1. このクラスを使用して新しいClassファイルを作成し、プロジェクトのどこからでもアクセスできるようにします。

    import UIKit
    
    class SharedControllers
    {
        static func navigateToRoot(viewController: UIViewController)
        {
            var nc = viewController.navigationController
    
            // If this is a normal view with NavigationController, then we just pop to root.
            if nc != nil
            {
                nc?.popToRootViewControllerAnimated(true)
                return
            }
    
            // Most likely we are in Modal view, so we will need to search for a view with NavigationController.
            let vc = viewController.presentingViewController
    
            if nc == nil
            {
                nc = viewController.presentingViewController?.navigationController
            }
    
            if nc == nil
            {
                nc = viewController.parentViewController?.navigationController
            }
    
            if vc is UINavigationController && nc == nil
            {
                nc = vc as? UINavigationController
            }
    
            if nc != nil
            {
                viewController.dismissViewControllerAnimated(false, completion:
                    {
                        nc?.popToRootViewControllerAnimated(true)
                })
            }
        }
    }
  2. プロジェクトのどこからでも使用:

    {
        ...
        SharedControllers.navigateToRoot(self)
        ...
    }

0

これは私のために働きました:

ルートビューコントローラーがナビゲーションコントローラーに埋め込まれている場合:

UINavigationController * navigationController = (UINavigationController *)[[[[UIApplication sharedApplication] windows] firstObject] rootViewController];
RootViewController * rootVC = (RootViewController *)[[navigationController viewControllers] firstObject];

それを忘れないでくださいkeyWindow推奨されていません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.