viewWillDisappear: determina se il controller di visualizzazione viene visualizzato o mostra un controller di visualizzazione secondaria

StackOverflow https://stackoverflow.com/questions/1816614

Domanda

Faccio fatica a trovare una buona soluzione a questo problema. Nel metodo -viewWillDisappear: di un controller di visualizzazione, devo 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 spuntato.

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

È stato utile?

Soluzione

È 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");
  }
}

Ciò è ovviamente possibile perché lo stack del controller di visualizzazione di UINavigationController (esposto attraverso la proprietà viewControllers) è stato aggiornato al momento della chiamata di viewWillDisappear.

Altri suggerimenti

Penso che il modo più semplice sia:

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

Swift:

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

Dalla documentazione di Apple in UIViewController.h:

  

" Questi quattro metodi possono essere utilizzati nell'aspetto di un controller di visualizzazione   callback per determinare se viene presentato, eliminato o aggiunto   o rimosso come controller di visualizzazione figlio. Ad esempio, un controller di visualizzazione   può verificare se sta scomparendo perché è stato eliminato o visualizzato   chiedendosi a suo avvisoWillDisappear: metodo controllando il   espressione ([self isBeingDismissed] || [self   . 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 farlo è il seguente:

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

Versione Swift 3:

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

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

Se vuoi solo sapere se la tua vista viene visualizzata, ho appena scoperto che self.navigationController è nil in viewDidDisappear , quando viene rimosso dalla pila di controller. Quindi questo è un semplice test alternativo.

(Lo scopro dopo aver provato ogni sorta di altre contorsioni. Sono sorpreso che non ci sia un protocollo del controller di navigazione per registrare un controller di visualizzazione per ricevere notifiche sui pop. Non puoi usare UINavigationControllerDelegate perché quello in realtà funziona davvero sul display.)

Swift 4

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

In Swift:

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

    super.viewWillDisappear(animated)

}

Trovo che la documentazione di Apple su questo sia 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)")
    }
}

Questa domanda è piuttosto vecchia ma l'ho vista per caso, quindi voglio pubblicare le migliori pratiche (afaik)

puoi semplicemente

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

Questo vale per iOS7 , non ho idea se si applica ad altri. Da quello che so, in viewDidDisappear la vista è già stata visualizzata. Ciò significa che quando esegui una query su self.navigationController.viewControllers otterrai un zero . Quindi controlla se è zero.

TL; DR

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

Segues può essere un modo molto efficace per gestire questo problema in iOS 6+. Se hai specificato l'identificatore segue in Identificatore di interfaccia, puoi verificarlo in preparForSegue .

- (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
    }
}

Suppongo che intendi dire che la tua vista viene spostata nello stack del controller di navigazione spingendo una nuova vista quando dici spinta nello stack. Suggerirei di usare il metodo viewDidUnload per aggiungere un'istruzione NSLog per scrivere qualcosa sulla console in modo da poter vedere cosa sta succedendo, potresti voler aggiungere un NSLog in viewWillDissappeer .

Ecco una categoria per realizzare la stessa cosa della 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top