2009-11-29 8 views
121

Non riesco a trovare una buona soluzione a questo problema. Nel metodo -viewWillDisappear: di un controller di visualizzazione, ho bisogno di trovare un modo per determinare se è perché un controller di visualizzazione viene inserito nello stack del controller di navigazione, o se è perché il controller di visualizzazione sta scomparendo perché è stato fatto scoppiare.viewWillDisappear: consente di determinare se il controller di visualizzazione viene visualizzato o mostra un controller di vista secondaria

Al momento sto impostando flag come isShowingChildViewController ma sta diventando piuttosto complicato. L'unico modo in cui penso di poterlo rilevare è nel metodo -dealloc.

risposta

219

È possibile utilizzare quanto segue.

- (void)viewWillDisappear:(BOOL)animated { 
    [super viewWillDisappear:animated]; 
    NSArray *viewControllers = self.navigationController.viewControllers; 
    if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) { 
    // View is disappearing because a new view controller was pushed onto the stack 
    NSLog(@"New view controller was pushed"); 
    } else if ([viewControllers indexOfObject:self] == NSNotFound) { 
    // View is disappearing because it was popped from the stack 
    NSLog(@"View controller was popped"); 
    } 
} 

Questo è, naturalmente, possibile perché pila vista controllore della UINavigationController (esposto attraverso la proprietà viewControllers) è stato aggiornato dal momento che viewWillDisappear viene chiamato.

+2

Perfetto! Non so perché non ci ho pensato! Immagino che non pensavo che lo stack sarebbe stato alterato fino a quando non fossero stati chiamati i metodi di sparizione! Grazie :-) –

+1

Ho appena provato a eseguire la stessa cosa ma in 'viewWillAppear' e sembrerebbe che se il controller di visualizzazione viene rivelato dal fatto che viene spinto o qualcosa sopra di esso viene spuntato, L'array viewControllers è lo stesso entrambi i modi! Qualche idea? –

+0

Devo anche notare che il controller di visualizzazione è persistente per tutta la durata dell'app, quindi non posso eseguire le mie azioni su 'viewDidLoad' poiché viene chiamato solo una volta! Hmm, difficile! –

-1

Immagino tu voglia dire che la tua vista viene spostata verso il basso nello stack del controller di navigazione premendo una nuova vista quando dici spinto in pila. Suggerirei di utilizzare il metodo viewDidUnload per aggiungere un'istruzione NSLog per scrivere qualcosa sulla console in modo da poter vedere cosa sta succedendo, si potrebbe voler aggiungere un NSLog a viewWillDissappeer.

16

Se si desidera sapere se la visualizzazione è spuntata, ho appena scoperto che self.navigationController è nil in viewDidDisappear, quando viene rimosso dalla pila di controller. Quindi questo è un semplice test alternativo.

(Questo scopro dopo aver provato ogni sorta di altre contorsioni. Mi sorprende che non c'è alcun protocollo controller di navigazione per registrare un controller di vista per essere notificato il pop. Non è possibile utilizzare UINavigationControllerDelegate perché che in realtà vero lavoro di visualizzazione.)

-1

Ecco una categoria per ottenere la stessa cosa come la risposta di sbrocket:

Intestazione:

#import <UIKit/UIKit.h> 

@interface UIViewController (isBeingPopped) 

- (BOOL) isBeingPopped; 

@end 

Fonte:

#import "UIViewController+isBeingPopped.h" 

@implementation UIViewController (isBeingPopped) 

- (BOOL) isBeingPopped { 
    NSArray *viewControllers = self.navigationController.viewControllers; 
    if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) { 
     return NO; 
    } else if ([viewControllers indexOfObject:self] == NSNotFound) { 
     return YES; 
    } 
    return NO; 
} 

@end 
116

Penso che il modo più semplice è:

- (void)viewWillDisappear:(BOOL)animated 
{ 
    [super viewWillDisappear:animated]; 
    if ([self isMovingFromParentViewController]) 
    { 
     NSLog(@"View controller was popped"); 
    } 
    else 
    { 
     NSLog(@"New view controller was pushed"); 
    } 
} 

Swift:

override func viewWillDisappear(animated: Bool) 
{ 
    super.viewWillDisappear(animated) 
    if isMovingFromParentViewController 
    { 
     print("View controller was popped") 
    } 
    else 
    { 
     print("New view controller was pushed") 
    } 
} 
+0

A partire da iOS 5 questa è la risposta, forse anche checkBeingDismissed – d370urn3ur

+3

Per iOS7 devo controllare [self.navigationController.viewControllers indexOfObject: self] == NSNotFound di nuovo perché l'app in background passerà anche questo test ma non rimuoverà da sola dallo stack di navigazione. –

+0

Neat and clean! – AsifHabib

0

Questa domanda è piuttosto vecchio ma ho visto per caso quindi voglio postare best practice (afaik)

si può fare solo

if([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) 
// view controller popped 
} 
+0

Ci sono molte risposte declassate, penso che sarà giusto menzionare il motivo per cui dovresti declassare la risposta. – Jiraheta

0

Questo vale per iOS7, nessuna idea se si applica a qualsiasi altro. Da quello che so, in viewDidDisappear la vista è già spuntata. Il che significa che quando si esegue una query su self.navigationController.viewControllers verrà visualizzato nil. Quindi controlla se è nulla.

TL; DR

- (void)viewDidDisappear:(BOOL)animated 
{ 
    [super viewDidDisappear:animated]; 
    if (self.navigationController.viewControllers == nil) { 
     // It has been popped! 
     NSLog(@"Popped and Gone"); 
    } 
} 
0

Segues può essere un modo molto efficace di trattare questo problema in iOS 6+. Se è stato specificato un particolare identificativo in Interface Builder, è possibile verificarlo in prepareForSegue.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    if ([segue.identifier isEqualToString:@"LoginSegue"]) { 
     NSLog(@"Push"); 
     // Do something specific here, or set a BOOL indicating 
     // a push has occurred that will be checked later 
    } 
} 
5

In Swift:

override func viewWillDisappear(animated: Bool) { 
    if let navigationController = self.navigationController { 
     if !contains(navigationController.viewControllers as! Array<UIViewController>, self) { 
     } 
    } 

    super.viewWillDisappear(animated) 

} 
+0

Assicurarsi di utilizzare come! invece di come – dfmuir

52

Dalla documentazione di Apple nel UIViewController.h:

"Questi quattro metodi possono essere utilizzati in apparenza di un controller di vista callback per determinare se si tratta di presentato, licenziato o aggiunto o rimosso come controller di visualizzazione figlio. Ad esempio, un controller di visualizzazione può verificare se sta scomparendo b perché è stato ignorato o fatto scoppiare chiedendosi nel suo viewWillDisappear: metodo controllando l'espressione ([self isBeingDismissed] || [Sé isMovingFromParentViewController]) "

- (BOOL)isBeingPresented NS_AVAILABLE_IOS(5_0);

- (BOOL)isBeingDismissed NS_AVAILABLE_IOS(5_0);

- (BOOL)isMovingToParentViewController NS_AVAILABLE_IOS(5_0);

- (BOOL)isMovingFromParentViewController NS_AVAILABLE_IOS(5_0);

Quindi sì, l'unico modo documentato per fare questo è il modo seguente:.

- (void)viewWillDisappear:(BOOL)animated 
{ 
    [super viewWillDisappear:animated]; 
    if ([self isBeingDismissed] || [self isMovingFromParentViewController]) { 
    } 
} 

Swift 3 Versione:

override func viewWillDisappear(_ animated: Bool) { 
    super.viewWillDisappear(animated) 

    if self.isBeingDismissed || self.isMovingFromParentViewController { 
    } 
} 
+1

Questa è la risposta appropriata. – mattyohe

3

Swift 3

override func viewWillDisappear(_ animated: Bool) 
    { 
     super.viewWillDisappear(animated) 
     if self.isMovingFromParentViewController 
     { 
      //View Controller Popped 
     } 
     else 
     { 
      //New view controller pushed 
     } 
    } 
1

trovo la documentazione di Apple su questo è difficile da capire. Questa estensione aiuta a vedere gli stati in ogni navigazione.

extension UIViewController { 
    public func printTransitionStates() { 
     print("isBeingPresented=\(isBeingPresented)") 
     print("isBeingDismissed=\(isBeingDismissed)") 
     print("isMovingToParentViewController=\(isMovingToParentViewController)") 
     print("isMovingFromParentViewController=\(isMovingFromParentViewController)") 
    } 
} 
Problemi correlati