2012-08-05 9 views
13

Sto scrivendo una semplice applicazione che ha 3 controller di vista. Il controller della vista radice è una vista tabella di base item listing. Al di fuori di questo controller di visualizzazione, spingo due diversi controller di visualizzazione in base all'interazione dell'utente: un controller di visualizzazione create item o un controller di visualizzazione view item.Come tornare al controller di visualizzazione radice, ma poi passare a una vista diversa?

Quindi, lo storyboard è simile a una V o qualcosa del genere.

Sul mio controller della vista create item, vorrei che tornasse al controller di visualizzazione radice quando l'utente crea un nuovo elemento, ma poi spinge al controller view item in modo che possa guardare l'elemento appena creato.

Non riesco a farlo funzionare. È abbastanza facile tornare al controller di visualizzazione radice, ma non riesco a spingere il controller view item.

Qualche idea? Ho incollato il mio codice, di seguito. La funzione pop funziona, ma la nuova vista non appare mai.

- (void) onSave:(id)sender { 

    CLLocation *currentLocation = [[LocationHelper sharedInstance] currentLocation]; 

    // format the thread object dictionary 
    NSArray* location = @[ @(currentLocation.coordinate.latitude), @(currentLocation.coordinate.longitude) ]; 
    NSDictionary* thread = @{ @"title": _titleField.text, @"text": _textField.text, @"author": @"mustached-bear", @"location": location }; 

    // send the new thread to the api server 
    [[DerpHipsterAPIClient sharedClient] postPath:@"/api/thread" 
             parameters:thread 
              success:^(AFHTTPRequestOperation *operation, id responseObject) { 

               // init thread object 
               Thread *thread = [[Thread alloc] initWithDictionary:responseObject]; 

               // init view thread controller 
               ThreadViewController *viewThreadController = [[ThreadViewController alloc] init]; 
               viewThreadController.thread = thread; 

               [self.navigationController popToRootViewControllerAnimated:NO]; 
               [self.navigationController pushViewController:viewThreadController animated:YES]; 

              } 
              failure:^(AFHTTPRequestOperation *operation, NSError *error) { 

               [self.navigationController popToRootViewControllerAnimated:YES]; 

              }]; 

} 
+0

Non creerei controller di vista diversi per "Crea elemento" e "Visualizza elemento". Vero che potresti voler vedere l'oggetto dopo averlo creato, ma c'è sempre un'altra possibilità che il tuo utente possa voler modificare l'oggetto dopo averlo visto. Sarebbe più semplice progettare un controller di visualizzazione per consentire la creazione, la visualizzazione e la modifica in un'unica vista. La maggior parte delle app la progetta in questo modo. Risparmia il tuo tempo seguendoti. – Rick

risposta

6

Un modo semplice per ottenere ciò che si vuole fare è quello di costruire qualche semplice logica nelle vostre principali controller di vista radice - (void) metodo viewWillAppear e utilizzare un callback delegato per capovolgere l'interruttore logica. fondamentalmente un "riferimento indietro" al controller di root. ecco un rapido esempio.

controller principale radice (considerare questo controller a) - e lo chiamano controllerA impostare una proprietà per tenere traccia dello stato di salto

@property (nonatomic) BOOL jumpNeeded; 

configurazione certa logica in

- (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; 
    self.jumpNeeded ? NSLog(@"jump needed") : NSLog(@"no jump needed"); 

    if (self.jumpNeeded) { 
     NSLog(@"jumping"); 
     self.jumpNeeded = NO; 
     [self performSegueWithIdentifier:@"controllerC" sender:self]; 
    } 
} 

Ora, in il tuo controller principale principale, quando viene selezionata una riga tableview, fai qualcosa di simile a questo quando premi il controllerB nella tua tabellaIl metodo selezionato ha selezionato

[self [email protected]"controllerB" sender:self]; 

quindi implementare la tua preparazione per il metodo segue

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 

    //setup controller B 
    if([segue.identifier isEqualTo:@"controllerB"]){ 
    ControllerB *b = segue.destinationViewController; 
    b.delegate = self; //note this is the back reference 
    } 

    //implement controller c here if needed 
} 

Ora passare a controllerB è necessario impostare una proprietà chiamata "delegato" per contenere il riferimento indietro ed è necessario importare il file di intestazione da il controller radice

#import "controllerA" 

@property (nonatomic,weak) controllerA *delegate; 

poi appena prima di pop torna a controllerA, si imposta il flag

self.delegate.jumpNeeded = YES; 
    [self.navigationController popViewControllerAnimated:YES]; 

e questo è tutto. Non devi fare nulla con controllerC. Ci sono alcuni altri modi per farlo, ma questo è abbastanza semplice per le tue esigenze. spero che funzioni per te

+0

Ho scelto questo come risposta, perché i delegati erano il percorso che ho finito per andare. Sebbene, ho abbandonato il push segue nel suo insieme e ho seguito un passo modale, per la vista 'create item'. – Ryan

+0

Sono contento che i suggerimenti ti abbiano portato in una direzione che ha funzionato per te. buona fortuna! – CocoaEv

0

Non penso che sia possibile, perché lo schiocco restituirà tutto.

Penso che un modo migliore sia quello di inserire i dati in una classe Singleton del modello, inserire il rootviewcontroller e ascoltare la fine del pop. Quindi si controlla se ci sono alcuni dati memorizzati sul modello in modo da sapere se è necessario inviare un nuovo viewcontroller.

6

Penso
[self.navigationController pushViewController:viewThreadController animated:YES]; utilizza un navigationController diverso da quello comunicato prima. Perché dopo popping al controller della vista radice si perde il controller di navigazione ci si trova in. Risolvi che l'utilizzo di questo codice al posto

UINavigationController *nav = self.navigationController; 
[self.navigationController popToRootViewControllerAnimated:NO]; 
[nav pushViewController:viewThreadController animated:YES]; 

Penso anche che questo voleva risolvere tutto il problema. Probabilmente riceverai un errore dicendo che due popping e push veloci possono invalidare il NavigationController.
E per risolvere ciò è possibile spingere il NavigationController nel metodo viewDidDissappear del 2 ° View Controller o inserirlo nel metodo viewDidAppear nel Main View Controller (elenco voci).

+0

Le mie conoscenze: quando si utilizza animato: SÌ, allora non funziona come previsto, ma animato: NO fa il lavoro. E poichè popToRoot è più corto, l'ho usato. Spero che sia d'aiuto! – kjoelbro

+0

Semplicemente usando popToRootController è la risposta qui credo.Non c'è bisogno di fare nulla di divertente con la vista. Stack e stack di controller possono funzionare normalmente come al solito. –

36

Se ho capito bene, si dispone di una pila di controller di vista:

A (root) - B - C - D - E 

E volete che diventi:

A (root) - F 

Destra? In tal caso:

NSArray *viewControllers = self.navigationController.viewControllers; 
NSMutableArray *newViewControllers = [NSMutableArray array]; 

// preserve the root view controller 
[newViewControllers addObject:[viewControllers objectAtIndex:0]]; 
// add the new view controller 
[newViewControllers addObject:viewThreadController]; 
// animatedly change the navigation stack 
[self.navigationController setViewControllers:newViewControllers animated:YES]; 
+0

Questo si animerà dalla vista E per visualizzare F. –

+2

^@LysannSchlegel che è il punto. Si anima da E-> F, ma poi se premi il pulsante Indietro, vai ad A anziché a E. In pratica, svuota il back stack fino alla visualizzazione genitore senza animazioni funky/impreviste in mezzo! – DiscDev

+1

La risposta di Dave è ottima, portala al livello successivo di riutilizzo con una categoria su UINavigationController: http://stackoverflow.com/a/25771209/1103584 – DiscDev

5

Condivisione di una categoria su UINavigationController basata sulla risposta di Dave DeLong che utilizziamo nella nostra applicazione per mantenere il pulsante Indietro sempre funzionante come richiesto.

@implementation UINavigationController (PushNewAndClearNavigationStackToParent) 

- (void) pushNewControllerAndClearStackToParent:(UIViewController*)newCont animated:(BOOL)animated 
{ 
    NSArray *viewControllers = self.viewControllers; 
    NSMutableArray *newViewControllers = [NSMutableArray array]; 
     
    // preserve the root view controller 
    [newViewControllers addObject:[viewControllers firstObject]]; 
    // add the new view controller 
    [newViewControllers addObject:newCont]; 
    // animatedly change the navigation stack 
    [self setViewControllers:newViewControllers animated:animated]; 
} 

@end 
1
NSArray *viewControllers = self.navigationController.viewControllers; 
NSMutableArray *newViewControllers = [NSMutableArray array]; 

// preserve the root view controller 
for(int i = 0; i < [viewControllers count];i++){ 
    if(i != [viewControllers count]-1) 
     [newViewControllers addObject:[viewControllers objectAtIndex:i]]; 
} 
// add the new view controller 
[newViewControllers addObject:conversationViewController]; 
// animatedly change the navigation stack 
[self.navigationController setViewControllers:newViewControllers animated:YES]; 
+0

Potresti per favore elaborare più la tua risposta aggiungendo un po 'più di descrizione della soluzione che fornisci? – abarisone

0

ho usato la risposta di Dave come ispirazione e ha fatto questo per Swift:

let newViewControllers = NSMutableArray() 
newViewControllers.addObject(HomeViewController()) 
newViewControllers.addObject(GroupViewController()) 
let swiftArray = NSArray(array:newViewControllers) as! Array<UIViewController> 
self.navigationController?.setViewControllers(swiftArray, animated: true) 
  1. Sostituire HomeViewController() con quello che vuoi il controller vista dal basso per essere
  2. Sostituire GroupViewController() con qualsiasi cosa desideri che il controller della vista superiore sia
0

Se ciò che si vuole fare è navigare all'interno dello stesso controller di navigazione ... è possibile accedere a navigationStack A.K.A. viewControllers e quindi imposta i viewcontrollers nell'ordine desiderato oppure aggiungi o rimuovi alcuni ... Questo è il modo più pulito e nativo per farlo.

 UINavigationController* theNav = viewControllerToDismiss.navigationController; 
     UIViewController* theNewController = [UIViewController new]; 
     UIViewController* rootView = theNav.viewControllers[0]; 
     [theNav setViewControllers:@[ 
            rootView, 
            theNewController 
            ] animated:YES]; 

fare tutte le convalide necessarie in modo da non ottenere alcuna eccezione.

Problemi correlati