2009-06-05 13 views
21

Ho un tabBarController con due schede, la prima delle quali contiene un'istanza di NavigatorController. Il navigatorController viene avviato con un viewController personalizzato "peersViewController" che elenca tutti i peer di rete su una tabellaView. Dopo aver selezionato un peer, un'istanza di "FilesListViewController" (che elenca i file nella directory c: \) viene inserita nello stack navigationController.UINavigationController popToRootViewController, quindi premere immediatamente una nuova vista

In questo fileListViewController ho un pulsante che consente di navigare per dire directory dei documenti. Per fare questo avevo telegrafato l'interfaccia di chiamare un gotoDirectory: (NSString *) Metodo di percorso nel RootViewController:

- (void)gotoDirectory:(NSString*)path { 
    [[self navigationController] popToRootViewControllerAnimated:YES]; 
    NSArray *files = [self getFilesFromPeerAtPath:path]; 
    FilesListViewController *filesVC = [[FilesListViewController alloc] initWithFiles:files]; 
    [[self navigationController] pushViewController:filesVC animated:YES]; 
    [filesVC release]; 
} 

Tuttavia, quando si preme il pulsante, il navigationController ha pop mio punto di vista al controller della vista di root , ma il FilesListViewController che ho istanziato non è stato visualizzato. Dal log, so che il metodo personalizzato initWithFiles è stato effettivamente chiamato e gli elementi di rete sono accaduti per ottenere i nomi dei file.

Qualcos'altro è un po 'strano. Ho provato a fare clic sulla seconda scheda e quindi a fare clic sulla prima scheda e su huala! i nomi dei file di cui avevo bisogno sono lì. Sembra che i dati e i fileListViewController siano stati effettivamente inseriti nello stack navigatorController, ma il display non è stato aggiornato ma bloccato sullo schermo di rootViewController (peersViewController).

Sto facendo qualcosa di sbagliato?

--Ben.

- Modificato come 15 minuti dopo aver postato la domanda. Avevo trovato una soluzione alternativa, ma mi disturba quel pop e poi push non funziona.

- (void)gotoDirectory:(NSString*)path { 
    PeersListViewController *rootViewController = (PeersListViewController*)[[[self navigationController] viewControllers] objectAtIndex:0]; 
    [[self navigationController] setViewControllers:[NSArray arrayWithObject:rootViewController]]; 
    FilesListViewController *filesVC = [[FilesListViewController alloc] initWithFiles:files]; 
    [[self navigationController] pushViewController:filesVC animated:YES]; 
    [filesVC release]; 
} 

Non sembra come il navigationController dovrebbe essere aggirato in questo modo, e probabilmente sarei dovuto liberare tutti i viewControllers che erano nella pila originale. Questo tuttavia funziona con il simulatore di iPhone 3.0.

Se sto usando questo codice, come dovrebbe essere gestita la versione di memoria? dovrei ottenere l'originale NSArray di viewcontrollers e rilasciare tutto?

risposta

10

Ho ottenuto un problema molto simile (ma senza utilizzare la scheda).

Ho tre viewController: main (root), form e result. quando la pila UINavigationController è

"principale -> risultato"

su un btnClick faccio un popToRootViewControllerAnimated poi una spinta del formViewCtrl. al fine di avere

"principale -> forma"

il titolo barra di navigazione e l'etichetta pulsante indietro sono corretti e l'evento del formViewCtrl sono chiamati. MA, continuo a vedere la vista principale.

Qui è la mia "soluzione"

Dopo aver fatto qualche prova, ho scoperto che , senza l'animazione per andare al rootViwCtrl questo lavoro bene. Quindi uso solo l'animazione per spingere viewCtrl.

iPhone 3.0, problema riscontrato sul simulatore del dispositivo &.

Se ho qualcosa di nuovo, aggiornerò/commenterò il mio post.

+2

Sì, è necessario eseguire il pop senza animazione (in modo che avvenga immediatamente) e quindi premere con animazione. Se si tenta di eseguire due modifiche dell'animazione insieme (che richiedono tempo per il completamento), la vista si troverà in cattivo stato. – Jason

+0

Esattamente come descritto, questo non funziona per me. Penso che sia un problema di temporizzazione sui cambi di stack (il codice di animazione di Apple è molto fragile, è implementato male) - questa tecnica può funzionare o meno a seconda di quanto altro sullo schermo, a quanto pare. – Adam

1

Ho trovato una soluzione alternativa ma non riesco a spiegare perché funzioni: 1. Prima spingere il controller necessario. 2. Quindi inserire quello che si desidera.

Questo è totalmente illogico, ma funziona per il mio caso. Solo per chiarire le cose, lo sto usando nel seguente scenario: Prima schermata -> Vai alla schermata di caricamento -> Seconda schermata Quando sono nella seconda schermata, non voglio avere la schermata di caricamento nello stack e quando si fa clic su Indietro dovrei andare alla prima schermata.

saluti, Vesko Kolev

+0

Questo davvero non dovrebbe funzionare. Ma lo fa. In 3.0, ho trovato che l'approccio classico (manipolare direttamente l'array viewControllers) non sempre funziona come previsto, quindi sto provando questa soluzione alternativa. – Adam

76

Il problema e soluzione a questo problema è in realtà estremamente semplice.

Chiamare [self.navigationController popToRootViewControllerAnimated:YES] set self.navigationController a nil. Quando successivamente si chiama [self.navigationController pushViewController:someOtherViewController] si invia effettivamente un messaggio a nil, che non fa nulla.

Per risolvere il problema, è sufficiente impostare un riferimento locale al navigationController e l'uso che, invece:

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

Come affermato da Jason, il popToRootViewController deve essere eseguita senza animazione per far funzionare correttamente.

Grazie a jpimbert on the Apple forums per averlo indicato.

+0

Questo ha funzionato per me !!! Grazie mille ... +1 Per Nick! – necixy

+1

Vorrei poter votare per più di una volta! Bella risposta. – akpb

+0

La soluzione giusta! –

1

La risposta di Nick Street funziona alla grande se si vuole popToRootViewController e successivamente si spinge un altro VC.

VC1 -> VC2 -> VC3: premere il pulsante di ritorno da VC3 => VC2, poi VC1, qui OK

Tuttavia, quando VC1 spinge VC2, che a sua volta spinge VC3, poi tornare a VC1 direttamente da VC3 non funziona come desiderato:

ho implementato in -(void)viewWillDisappear:(BOOL)animated di VC3:

-(void)viewWillDisappear:(BOOL)animated{ 

    ... 
    [self.navigationController popToRootViewControllerAnimated:YES]; 
} 

ho anche provato per la sua attuazione nel "pulsante indietro", stesso risultato: su colpire il pulsante indietro da VC3 per tornare a VC1: si rompe. Il VC attuale è VC1, ma la barra di navigazione è ancora VC2. Giocando con altre combinazioni, ottengo il navBar di VC1 su VC2. Pasticcio totale

Loda menzionava qualcosa sul tempismo. Penso che questo sia il problema principale qui. Ho provato un paio di cose, quindi forse mi manca qualcosa qui, ma questo è ciò che ha funzionato per me, finalmente:

In VC3:

-(void)viewWillDisappear:(BOOL)animated { 

    [super viewWillDisappear:animated]; 
    // notify VC2 
    [[NSNotificationCenter defaultCenter] postNotificationName:backFromV3 object:self]; 
} 

In VC2:

-(void)viewDidLoad { 

    ... 

    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(backFromV3) 
               name:@"BackFromV3" 
               object:nil]; 
} 

-(void)backFromV3{ 
    [NSTimer scheduledTimerWithTimeInterval:0.5 
           target:self 
           selector:@selector(backToRootViewController) 
           userInfo:nil 
           repeats:NO]; 
} 

-(void)backToVC1 { 
    self.navigationItem.rightBarButtonItem = nil; 
    [self.navigationController popToRootViewControllerAnimated:YES]; 
} 

Naturalmente, effettuare la pulizia necessaria.

Il timer è fondamentale qui. Se 0, si rompe. 0.5 sembra essere a posto.

Che funziona perfettamente per me. Un po 'pesante, ma non sono stato in grado di trovare nulla che faccia il trucco.

1

Si può effettivamente mantenere l'animazione "Torna indietro", seguita dall'animazione "Vai avanti" in pratica ritardando l'animazione push fino a quando l'animazione pop è completa. Ecco un esempio:

(Nota: ho una variabile NSString chiamata "transitionTo" nella mia appDelegate che è inizialmente impostata su @ "") ... Innanzitutto, imposta tale variabile su una NSString che puoi rilevare per dopo. Poi, pop il controller per darvi un bel passaggio schermo torna alla radice:

appDelegate.transitionTo = @"Another"; 
[detailNavigationController popToRootViewControllerAnimated:YES]; 

poi dentro la classe del RootViewController, utilizzare il metodo viewDidAppear:

-(void)viewDidAppear:(BOOL)animated 
{ 
    AppDelegate *appDelegate =(AppDelegate*) [UIApplication sharedApplication].delegate; 
    if([appDelegate.transitionTo isEqualToString:@"Another"]) 
    { 
     [self transitionToAnotherView]; 
     appDelegate.transitionTo = @""; 
    } 
} 

-(void)transitionToAnotherView 
{ 
    // Create and push new view controller here 
    AnotherViewController *controller = [[AnotherViewController alloc] init]; 

    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Home" style:UIBarButtonItemStyleBordered target:nil action:nil]; 
    [self.navigationItem setBackBarButtonItem:backButton]; 

    [[self navigationController] pushViewController:controller animated:YES]; 
} 

Quindi, fondamentalmente, pop alla radice. ..quando la transizione termina su "viewDidAppear" ... quindi premi la vista successiva. Mi è capitato di tenere una variabile per dirti quale vista vuoi passare (con @ "" che significa non fare una transizione nel caso in cui voglio rimanere su questo schermo).

3

Vedo che questa domanda su popping alla radice e quindi su push su un nuovo ViewController è piuttosto diffusa, e questo post è visto molto, quindi volevo aggiungere il mio bit per aiutare altri nuovi ragazzi, specialmente quelli che usano Xcode 4 e uno storyboard.

In Xcode 4, si dispone di uno storyboard. Supponiamo di avere questi controller di visualizzazione: HomeViewController, FirstPageViewController, SecondPageViewController. Assicurati di fare clic su ognuno di essi e assegnare un nome ai loro identificatori andando nel pannello Utilità-> Impostazioni Impostazioni. Diremo che si chiamano Home, First e Second.

Sei a casa, quindi vai su Prima, poi vuoi essere in grado di andare in Secondo e poter premere il pulsante Indietro per tornare a Home. Per fare ciò, si desidera modificare il codice in FirstPageViewController.

Per espandere l'esempio, creare un pulsante in FirstPageViewController nello storyboard. Ctrl-trascina quel pulsante in FirstPageViewController.m. Lì, il seguente codice otterrà il risultato desiderato:

// Remember to add #import "SecondPageViewController.h" at the top 
    SecondPageViewController *secondView = [self.storyboard instantiateViewContorllerWithIdentifier:@"Second"]; 
    UINavigationController *navigationController = self.navigationController; 
    NSArray *array = [navigationController viewControllers]; 
    // [array objectAtIndex:0] is the root view controller 
    NSArray *viewControllersStack = [NSArray arrayWithObjects:[array objectAtIndex:0], secondView, nil]; 
    [navigationController setViewControllers:viewControllersStack animated:YES]; 

sostanza, si sta afferrando i controller di vista, disponendoli in una pila nell'ordine desiderato, e poi avere l'uso del controller di navigazione che stack per navigazione. È un'alternativa a spingere e scoppiare.

Problemi correlati