ViewWillDisappear: Определяет, будет ли отображаться контроллер просмотра или показывается контроллер подзадачи

Я изо всех сил пытаюсь найти хорошее решение этой проблемы. В методе диспетчера вида -viewWillDisappear: мне нужно найти способ определить, происходит ли это из-за того, что контроллер представления вставляется в стек контроллера навигатора или он вызван тем, что диспетчер представлений исчезает, поскольку он был выбит.

В настоящий момент я устанавливаю флаги, такие как isShowingChildViewController, но это становится довольно сложным. Единственный способ, по-моему, обнаружить его в методе -dealloc.

Ответ 1

Вы можете использовать следующее.

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

Это, конечно, возможно, потому что стек контроллера представления UINavigationController (открытый через свойство viewControllers) был обновлен к тому времени, когда вызывается viewWillDisappear.

Ответ 2

Я думаю, что самый простой способ это:

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

Ответ 3

Из документации Apple в UIViewController.h:

"Эти четыре метода могут использоваться в представлении контроллера вида обратные вызовы, чтобы определить, будет ли он представлен, отклонен или добавлен или удаляется как контроллер детского представления. Например, контроллер вида может проверить, исчезает ли оно, потому что оно было отклонено или выскочено запросив себя в своем представленииWillDisappear: метод, проверив выражение ([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);

Итак, да, единственный документированный способ сделать это:

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

Версия Swift 3:

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

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

Ответ 4

Если вы просто хотите узнать, появляется ли ваше представление, я только что обнаружил, что self.navigationController есть nil в viewDidDisappear, когда он удаляется из стека контроллеров. Так что простой альтернативный тест.

(Это я обнаружил после того, как пробовал всевозможные другие искажения.Я удивлен, нет никакого протокола контроллера навигации, чтобы зарегистрировать контроллер вида, который будет уведомлен о появлении попсов. Вы не можете использовать UINavigationControllerDelegate, потому что на самом деле работает реальная работа.)

Ответ 5

Swift 4

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

Ответ 6

В Swift:

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

    super.viewWillDisappear(animated)

}

Ответ 7

Я считаю, что документация Apple по этому вопросу трудно понять. Это расширение помогает видеть состояния при каждой навигации.

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

Ответ 8

Этот вопрос довольно старый, но я видел его случайно, поэтому хочу опубликовать лучшую практику (afaik)

вы можете просто сделать

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

Ответ 9

Это относится к iOS7, не знаю, применимо ли оно к другим. Из того, что я знаю, в viewDidDisappear представление уже было вытолкнуто. Это означает, что при запросе self.navigationController.viewControllers вы получите nil. Так что просто проверьте, нет ли этого.

TL; DR

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

Ответ 10

Segues может быть очень эффективным способом решения этой проблемы в iOS 6+. Если вы указали конкретный segue идентификатор в Interface Builder, вы можете проверить его в 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
    }
}

Ответ 11

Спасибо @Bryan Генри, все еще работает в Swift 5

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if let controllers = navigationController?.children{
            if controllers.count > 1, controllers[controllers.count - 2] == self{
                // View is disappearing because a new view controller was pushed onto the stack
                print("New view controller was pushed")
            }
            else if controllers.firstIndex(of: self) == nil{
                // View is disappearing because it was popped from the stack
                print("View controller was popped")
            }
        }

    }

Ответ 12

Я предполагаю, что вы имеете в виду, что ваше представление перемещается вниз по стеку контроллера навигации, нажимая новый вид, когда вы говорите, нажав на стек. Я бы предложил использовать метод viewDidUnload для добавления оператора NSLog для записи чего-либо в консоль, чтобы вы могли видеть, что происходит, вы можете добавить NSLog в viewWillDissappeer.

Ответ 13

Вот категория, чтобы выполнить то же самое, что и ответ sbrocket:

Заголовок:

#import <UIKit/UIKit.h>

@interface UIViewController (isBeingPopped)

- (BOOL) isBeingPopped;

@end

Источник:

#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