Просмотр исчезнет:Определите, извлекается ли контроллер представления или отображается контроллер вложенного представления

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

Вопрос

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

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

Это было полезно?

Решение

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

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

Другие советы

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

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

Быстрый:

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

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

  

" эти четыре метода могут использоваться в представлении контроллера представления   обратные вызовы, чтобы определить, представлен ли он, отклонен или добавлен   или удален как дочерний контроллер представления. Например, контроллер представления   может проверить, исчезает ли он, потому что он был уволен или выскочил   спрашивая себя в его viewWillDisappear: метод, проверяя   выражение ([self isBeingDismissed] || [self   . IsMovingFromParentViewController]) & Quot;      

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

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

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

Swift 4

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

В Swift:

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

    super.viewWillDisappear(animated)

}

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

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

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

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

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

Это относится к 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");
    }
 }

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

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

Вот категория, позволяющая выполнить то же самое, что и ответ 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top