viewWillDisappear: Determinar se o controlador de visualização está a ser estalado ou está mostrando um controlador de sub-vista

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

Pergunta

Eu estou lutando para encontrar uma boa solução para este problema. No método -viewWillDisappear: de um controlador de vista, eu preciso encontrar uma maneira de determinar se é porque um controlador de vista está sendo empurrado na pilha do controlador de navegação, ou se é porque o controlador de vista está desaparecendo porque foi estalado.

No momento eu estou definindo bandeiras como isShowingChildViewController mas está ficando bastante complicado. A única maneira que eu acho que pode detectá-lo é no método -dealloc.

Foi útil?

Solução

Você pode usar o seguinte.

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

Esta é, obviamente, possível porque pilha de controlador de vista do UINavigationController (exposto através da propriedade viewControllers) foi atualizado no momento em que viewWillDisappear é chamado.

Outras dicas

Eu acho que a maneira mais fácil é:

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

A partir de Documentação da Apple em UIViewController.h:

"Esses quatro métodos podem ser usados ??na aparência de um controlador de vista retornos de chamada para determinar se ele está sendo apresentado, demitido, ou adicionadas ou removidos como um controlador de vista criança. Por exemplo, um controlador de vista pode verificar se ele está desaparecendo porque ele foi demitido ou estalado perguntando-se na sua viewWillDisappear: método, verificando a expressão ([auto isBeingDismissed] || [auto 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);

Então, sim, a única maneira documentada para fazer isso é da seguinte maneira:

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

Swift 3 version:

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

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

Se você só quer saber se sua visão está ficando bateu, eu só descobri que self.navigationController é nil em viewDidDisappear, quando é removido da pilha de controladores. Então isso é um teste alternativo simples.

(Isso eu descobrir depois de tentar todos os tipos de outros contorções. Estou surpreso não há nenhum protocolo de controlador de navegação para registrar um controlador de exibição para ser notificado sobre POPs. Você não pode usar UINavigationControllerDelegate porque isso realmente faz trabalho de exibição real.)

Swift 4

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

Em Swift:

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

    super.viewWillDisappear(animated)

}

I encontrar a documentação da Apple sobre isso é difícil de entender. Esta extensão ajuda a ver os estados em cada navegação.

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

Esta questão é bastante antigo, mas eu vi isso por acidente assim que eu quero postar melhores práticas (afaik)

você pode apenas fazer

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

Isso se aplica a iOS7 , nenhuma idéia se ela se aplica a quaisquer outros. Pelo que eu sei, em viewDidDisappear a visão já foi estalado. Que significa que quando você consulta self.navigationController.viewControllers você receberá um nil. Então, basta verificar se é nulo.

TL; DR

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

Segues pode ser uma maneira muito eficaz de lidar com este problema no iOS 6 +. Se você tiver dado o segue particular um identificador no Interface Builder você pode verificar-lo em 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
    }
}

Eu suponho que você quer dizer que a sua visão está sendo movido para baixo pilha do controlador de navegação pela empurrando um novo ponto de vista quando você diz empurrado na pilha. Sugiro usar o método viewDidUnload para adicionar uma declaração NSLog para escrever algo para o console para que você possa ver o que está acontecendo, você pode querer adicionar um NSLog para viewWillDissappeer.

Aqui está uma categoria para realizar a mesma coisa como a resposta da sbrocket:

Cabeçalho:

#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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top