Come posso ottenere RootViewController da un controller push?


137

Quindi, invio un controller di visualizzazione da RootViewController come:

[self.navigationController pushViewController: anotherViewController animato: SÌ];

MA, DA anotherViewControllerora, voglio accedere nuovamente a RootViewController.

sto provando

// (all'interno di un altro ViewController ora)
/// RootViewController * root = (RootViewController *) self.parentViewController; // No.
// err
RootViewController * root = (RootViewController *) [self.navigationController.viewControllers objectAtIndex: 0]; // SÌ!! Funziona

Non sono sicuro del perché funzioni e non sono sicuro che sia il modo migliore per farlo. Qualcuno può commentare un modo migliore per ottenere il RootViewController da un controller che hai inserito nel controller di navigazione di RootViewController e se il modo in cui l'ho fatto è affidabile o no?


Quello che hai fatto otterrà in modo affidabile il controller della vista radice (il primo nella gerarchia di navigazione), se vuoi avere accesso al controller della vista "indietro", vedi la mia risposta.
Ben S,

Risposte:


133

Utilizzare la proprietà viewControllers di UINavigationController. Codice di esempio:

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

Questo è il modo standard per ottenere il controller di visualizzazione "indietro". Il motivo objectAtIndex:0funziona perché il controller di visualizzazione a cui stai tentando di accedere è anche quello principale, se tu fossi più profondo nella navigazione, la vista posteriore non sarebbe la stessa della vista principale.


6
:) ty. Sembra ancora confuso - :) Volevo davvero che un membro "ufficiale" facesse il lavoro, qualcosa come self.navigationController.rootViewController, ma ahimè, niente del genere ..
bobobobo

62
Il codice sopra è errato. rootViewControllermanca *prima di esso e l'indice dovrebbe essere solo 0. Il codice nella domanda è corretto:RootViewController *root = (RootViewController *)[navigationController.viewControllers objectAtIndex:0]
ma11hew28

2
Concordato: il codice sopra riportato restituisce il controller della vista padre , non il controller della vista radice come richiesto dall'OP. Tuttavia, questo è quello che Ben S ha detto che farà, ma non l'ha sottolineato abbastanza.
Ivan Vučica,

La seconda riga dovrebbe contenere: UIViewController * rootViewController = [viewControllers objectAtIndex: viewControllers.count - 1];
Billy,

177

Versione rapida:

var rootViewController = self.navigationController?.viewControllers.first

Versione ObjectiveC:

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

Dove self è un'istanza di un UIViewController incorporato in un UINavigationController.


Posso ottenere il NavigationController di un altro ViewController da una classe diversa?
Sasquatch,

Qualsiasi sottoclasse UIViewController avrà una proprietà navigationController, che punta alla sua prima parentViewController corrispondente alla classe UINavigationController.
dulgan,

12

Una versione leggermente meno brutta della stessa cosa menzionata praticamente in tutte queste risposte:

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

nel tuo caso, probabilmente farei qualcosa del tipo:

all'interno della sottoclasse di UINavigationController :

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

allora puoi usare:

UIViewController *rootViewController = [self.navigationController rootViewController];

modificare

OP ha richiesto una proprietà nei commenti.

se vuoi, puoi accedervi tramite qualcosa di simile self.navigationController.rootViewControllersemplicemente aggiungendo una proprietà di sola lettura alla tua intestazione:

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

8

Per tutti coloro che sono interessati a una rapida estensione, questo è quello che sto usando ora:

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

1
Grazie! Inoltre puoi rimuovere "as? UIViewController"
atereshkov il

3

In aggiunta alla @ di dulgan risposta, è sempre un approccio buono da usare firstObjectsopra objectAtIndex:0, perché mentre i rendimenti primo nil se non v'è alcun oggetto nella matrice, quest'ultima lancia un'eccezione.

UIViewController *rootViewController = self.navigationController.rootViewController;

In alternativa, sarebbe un grande vantaggio per te creare una categoria denominata UINavigationController+Additionse definire il tuo metodo in questo.

@interface UINavigationController (Additions)

- (UIViewController *)rootViewController;

@end

@implementation UINavigationController (Additions)

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

@end

Ho appena aggiunto questa parte senza leggere la tua risposta, hai perfettamente ragione con "firstObject" migliore di [0]
dulgan,

1

Che ne dici di chiedere al singleton UIApplication la sua keyWindow , e da quella UIWindow chiedere il controller di visualizzazione root (la sua proprietà rootViewController ):

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

come ottenere il controller di navigazione?
Yestay Muratov,

Questo è un suggerimento sbagliato come se il mio rootviewcontroller dell'applicazione fosse UITabBarViewController?
Sandeep Singh Rana,

1

Qui ho ideato un metodo universale per navigare da qualsiasi luogo alla radice.

  1. Si crea un nuovo file di classe con questa classe, in modo che sia accessibile da qualsiasi parte del progetto:

    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. Utilizzo da qualsiasi parte del progetto:

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

0

Questo ha funzionato per me:

Quando il mio controller di visualizzazione radice è incorporato in un controller di navigazione:

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

Ricorda che keyWindowè deprecato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.