viewWillDisappear:确定是正在弹出视图控制器还是正在显示子视图控制器

时间:2009-11-29 20:09:13

标签: ios iphone cocoa-touch uiviewcontroller uikit

我很难找到解决这个问题的好方法。在视图控制器的-viewWillDisappear:方法中,我需要找到一种方法来确定是否因为视图控制器被推到导航控制器的堆栈上,或者是否因为视图控制器正在消失而因为它已被弹出

目前我正在设置isShowingChildViewController等标志,但它变得相当复杂。我认为可以检测到它的唯一方法是使用-dealloc方法。

13 个答案:

答案 0 :(得分:228)

您可以使用以下内容。

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

当然,这是可能的,因为在调用viewWillDisappear时,UINavigationController的视图控制器堆栈(通过viewControllers属性公开)已经更新。

答案 1 :(得分:128)

我认为最简单的方法是:

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

答案 2 :(得分:57)

来自UIViewController.h中的Apple文档:

  

"这四种方法可用于视图控制器的外观   回调以确定它是否被呈现,被驳回或添加   或作为子视图控制器删除。例如,视图控制器   可以检查它是否因为被解雇或弹出而消失   通过检查自己在viewWillDisappear:方法中询问自己   表达式([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 { 
    }
}

答案 3 :(得分:18)

如果您只是想知道自己的观点是否被弹出,我刚刚发现self.navigationController nilviewDidDisappear中,当它从控制器堆栈中删除时。所以这是一个简单的替代测试。

(这是我在尝试各种其他扭曲后发现的。我很惊讶没有导航控制器协议来注册视图控制器以通知pop。你不能使用UINavigationControllerDelegate因为它实际上是真的展示工作。)

答案 4 :(得分:11)

Swift 4

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

答案 5 :(得分:6)

在斯威夫特:

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

    super.viewWillDisappear(animated)

}

答案 6 :(得分:2)

我发现Apple的文档很难理解。此扩展程序有助于查看每个导航中的状态。

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

答案 7 :(得分:1)

这个问题相当陈旧,但我偶然看到它,所以我想发布最佳实践(afaik)

你可以做到

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

答案 8 :(得分:1)

这适用于 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");
    }
 }

答案 9 :(得分:1)

Segues可以是在iOS 6+中处理此问题的一种非常有效的方法。如果您在Interface Builder中为特定的segue指定了标识符,则可以在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
    }
}

答案 10 :(得分:1)

感谢@Bryan Henry,仍然可以在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")
            }
        }

    }

答案 11 :(得分:-1)

我认为你的意思是当你说推入一个新的视图时,你的视图被移动到导航控制器的堆栈中。我建议使用viewDidUnload方法添加NSLog语句来向控制台写一些东西,这样你就可以看到发生了什么,你可能想要NSLog添加viewWillDissappeer }}

答案 12 :(得分:-1)

这是一个与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