52

假设我有一个带有 2 个视图控制器的导航控制器堆栈:VC2 位于顶部,VC1 位于下方。我可以在 VC1 中包含哪些代码来检测 VC2 刚刚从堆栈中弹出吗?

由于我试图从 VC1 的代码中检测 VC2 的弹出,因此viewWillAppearviewDidAppear之类的东西似乎不起作用,因为每次显示 VC1 时都会触发这些方法,包括首次将其推入堆栈时。

编辑:我原来的问题似乎不是很清楚。这就是我想要做的:确定由于 VC2 从堆栈顶部弹出而显示 VC1 的时间。这就是我不想做的事情:确定何时显示 VC1,因为它被推到了堆栈的顶部。我需要一些方法来检测第一个动作而不是第二个动作。

注意:我并不特别关心 VC2,它可以是任何数量的其他 VC 从堆栈中弹出,我关心的是当 VC1 由于其他一些 VC 开始弹出而再次成为堆栈顶部时最佳。

4

10 回答 10

63

iOS 5 引入了两种新方法来处理这种情况。您正在寻找的是-[UIViewController isMovingToParentViewController]. 从文档

isMovingToParentViewController

返回一个布尔值,指示视图控制器正在添加到父级。

- (BOOL)isMovingToParentViewController

返回值
如果视图控制器出现是因为它是作为容器视图控制器的子级添加的,否则为否。

讨论
此方法仅在从以下方法内部调用时返回 YES:

-viewWillAppear:
-viewDidAppear:

在您的情况下,您可以-viewWillAppear:像这样实现:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    if (self.isMovingToParentViewController == NO)
    {
        // we're already on the navigation stack
        // another controller must have been popped off
    }
}

编辑:这里有一个微妙的语义差异需要考虑——您是否对 VC2 特别从堆栈中弹出这一事实感兴趣,或者您是否希望在每次 VC1 因任何控制器弹出而被显示时都得到通知?在前一种情况下,委托是一个更好的解决方案。如果您从不打算重用 VC2,那么对 VC1 的直接弱引用也可以工作。

编辑 2:我通过反转逻辑而不是提前返回来使示例更加明确。

于 2012-09-12T04:20:03.430 回答
15

isMovingTo/FromParentViewController 不适用于推送和弹出导航控制器堆栈。

这是一种可靠的方法(不使用委托),但它可能仅限于 iOS 7+。

UIViewController *fromViewController = [[[self navigationController] transitionCoordinator] viewControllerForKey:UITransitionContextFromViewControllerKey];

if ([[self.navigationController viewControllers] containsObject:fromViewController])
{
    //we're being pushed onto the nav controller stack.  Make sure to fetch data.
} else {
    //Something is being popped and we are being revealed
}

就我而言,使用委托意味着让视图控制器的行为与拥有导航堆栈的委托更紧密地耦合,我想要一个更独立的解决方案。这行得通。

于 2014-10-10T21:42:57.970 回答
7

解决此问题的一种方法是为 VC2 声明一个委托协议,如下所示:

在 VC1.h

@interface VC1 : UIViewController <VC2Delegate> {
...
}

在 VC1.m

-(void)showVC2 {
    VC2 *vc2 = [[VC2 alloc] init];
    vc2.delegate = self;
    [self.navigationController pushViewController:vc2 animated:YES];
}

-(void)VC2DidPop {
    // Do whatever in response to VC2 being popped off the nav controller
}

在 VC2.h

@protocol VC2Delegate <NSObject>
-(void)VC2DidPop;
@end

@interface VC2 : UIViewController {

    id<VC2Delegate> delegate;
}

@property (nonatomic, assign) id delegate;

...

@end

VC2.m

-(void)viewDidUnload {
    [super viewDidUnload];
    [self.delegate VC2DidPop];
}

这里有一篇关于协议和委托基础的好文章。

于 2012-09-12T04:09:10.397 回答
5

您还可以在正在弹出的视图控制器中检测到

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    if ([self isMovingFromParentViewController]) {
        ....
    }
}
于 2016-09-06T06:59:17.727 回答
1

这对我有用

UIViewController *fromViewController = [[[self navigationController] transitionCoordinator] viewControllerForKey:UITransitionContextFromViewControllerKey];
if (![[self.navigationController viewControllers] containsObject:fromViewController] && !self.presentedViewController)
{
  //Something is being popped and we are being revealed 
}
于 2017-05-25T11:56:23.213 回答
0

您可以专门为您的 VC2 添加一个 NSNotification 观察者。

// pasing the "VC2" here will tell the notification to only listen for notification from
// VC2 rather than every single other objects
[[NSNotitificationCenter defaultCenter] addObserver:self selector:@selector(doSomething:) object:VC2];

现在在你的 VC2 的视图中会消失,你可以发布一个通知:

-(void)viewWillDisappear
{
    [[NSNotificationCenter defaultCenter] postNotificationNamed:@"notif_dismissingVC2" object:nil];
}
于 2012-09-12T04:31:38.753 回答
0

你具体想做什么?

如果您试图检测 VC1 即将显示,这个答案应该对您有所帮助。使用UINavigationControllerDelegate

如果您试图检测 VC2 即将被隐藏,我会使用viewWillDisappear:VC2 的。

于 2012-09-12T03:52:54.157 回答
0

迅速 3

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if self.isMovingToParentViewController {
            print("View is moving to ParentViewControll")
        }
}
于 2017-05-11T08:59:00.240 回答
0

我遇到了同样的情况,但有更具体的用例。在我的例子中,我们想确定当用户点击 VC2 的后退按钮时是否出现/显示了 VC1,其中 VC2 在 VC1 上被推到 navigationController 上。

所以我根据我的需要使用了snarshad 的答案来定制。这是swift 3viewDidAppear中 VC1中的代码。

// VC1: ParentViewController
// VC2: ChildViewController

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

        if let transitionCoordinator = navigationController?.transitionCoordinator,
            let fromVC = transitionCoordinator.viewController(forKey: UITransitionContextViewControllerKey.from),
            let toVC = transitionCoordinator.viewController(forKey: UITransitionContextViewControllerKey.to),
            fromVC is ChildViewController,
            toVC is ParentViewController {

            print("Back button pressed on ChildViewController, and as a result ParentViewController appeared")
        }
    }
于 2017-09-08T11:02:39.573 回答
-1

是的,在VC1中你可以检查VC2是否被弹出。UINavigationController 有一种方法viewControllers将返回推送的控制器数组,这些控制器在堆栈中(即已被推送)。

所以你通过比较类来迭代循环。如果VC2存在,将有匹配,否则没有。

于 2012-09-12T04:58:55.903 回答