ViewWillDisaper: 确定是否弹出视图控制器或显示子视图控制器

我正在努力寻找解决这个问题的好办法。在视图控制器的 -viewWillDisappear:方法中,我需要找到一种方法来确定是因为视图控制器被推到了导航控制器的堆栈上,还是因为视图控制器被弹出而消失。

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

91562 次浏览

我假设您的意思是,当您说推送到堆栈上时,通过推送一个新的视图,您的视图正在沿着导航控制器的堆栈向下移动。我建议使用 viewDidUnload方法添加一个 NSLog语句来向控制台写入一些内容,这样您就可以看到正在发生什么,您可能希望向 viewWillDissappeer添加一个 NSLog

您可以使用以下内容。

- (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 的视图控制器堆栈(通过 viewController 属性公开)在调用 viewWillDisaper 时已经更新。

如果您只是想知道您的视图是否弹出,我刚刚发现 self.navigationControllerviewDidDisappear中的 nil,当它从控制器堆栈中删除时。这是一个简单的替代测试。

(这是我在尝试了各种其他的柔术后发现的。我很惊讶没有导航控制器协议来注册一个视图控制器来通知弹出窗口。您不能使用 UINavigationControllerDelegate,因为它实际上做的是真正的显示工作。)

这里有一个类别可以完成 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

我认为最简单的方法是:

 - (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 isMovingFromParent
{
print("View controller was popped")
}
else
{
print("New view controller was pushed")
}
super.viewWillDisappear(animated)
}

这个问题很老了,但是我是偶然看到的,所以我想发布最佳实践(afaik)

你可以这么做

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

这适用于 IOS7,不知道它是否适用于其他任何一个。据我所知,在 viewDidDisappear视图已经弹出。这意味着当您查询 self.navigationController.viewControllers时,您将得到一个 nil。检查一下是否为零。

DR

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

Segues 是 iOS6 + 中处理这个问题的一个非常有效的方法。如果你已经在 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
}
}

斯威夫特:

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


super.viewWillDisappear(animated)


}

来自 UIViewController.h 的苹果文档:

”这四个方法可以在视图控制器的外观中使用 回调以确定是否正在显示、解散或添加它 或作为子视图控制器移除。例如,视图控制器 可以检查它是否正在消失,因为它被解散或弹出 方法通过检查 表达式([ self isBeingDismiss ] | | [ 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 {
}
}

Swift 4

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

我发现苹果在这方面的文档很难理解,这个扩展可以帮助我们看到每个导航栏的状态。

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

谢谢@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")
}
}


}