web-dev-qa-db-ja.com

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

だから、私はRootViewControllerからView Controllerを次のようにプッシュします:

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

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

私はしようとしています

 //(今すぐanotherViewController内)
 /// RootViewController * root =(RootViewController *)self.parentViewController; // No。
 // err 
 RootViewController * root =(RootViewController *)[self.navigationController.viewControllers objectAtIndex:0]; // はい!!できます

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

132
bobobobo

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

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

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

132
Ben S

迅速なバージョン:

var rootViewController = self.navigationController?.viewControllers.first

ObjectiveCバージョン:

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

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

168
dulgan

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

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

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

INavigationControllerサブクラス内

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

次に使用できます:

UIViewController *rootViewController = [self.navigationController rootViewController];

編集

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

必要に応じて、ヘッダーに読み取り専用プロパティを追加するだけで、self.navigationController.rootViewControllerなどの方法でこれにアクセスできます。

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

Swift拡張機能に興味があるすべての人にとって、これは私が今使用しているものです。

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

@ dulgan's answerへの追加として、firstObject over 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
3
ozgur

IApplicationsingletonkeyWindow を要求し、そこから IWindow にルートビューコントローラー(its rootViewController property):

UIViewController root = [[[UIApplication sharedApplication] keyWindow] rootViewController];
1
Basil Bourque

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

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

    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)
        ...
    }
    
1
Maris