iOS如何在顶视图控制器popup时以编程方式检测?

假设我有一个带有2个视图控制器的导航控制器堆栈:VC2在顶部,VC1在下面。 VC1中是否有代码可以检测到VC2刚从堆栈中popup?

由于我试图从VC1的代码中检测到VC2的popup,看起来像viewWillAppearviewDidAppear这样的东西将不起作用,因为这些方法每次显示VC1时都会触发,包括当它被第一次推入堆栈时。

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

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

iOS 5引入了两种新的方法来处理这种types的情况。 你正在寻找的是-[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特别是从堆栈中popup,或者你想通知每次VC1显示任何控制器popup的结果吗? 在前一种情况下,代表团是一个更好的解决办法。 如果你从不打算重复使用VC2,那么直接引用VC1也是可行的。

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

isMovingTo / FromParentViewController不能用于推送和popup导航控制器堆栈。

这是一个可靠的方法(不使用代理),但它可能只是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 } 

在我的情况下,使用委托意味着视图控制器的行为与拥有导航堆栈的委托更紧密地耦合,我想要一个更独立的解决scheme。 这工作。

有一种方法可以解决这个问题,那就是为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]; } 

这里有一个关于协议和代表的基础知识的好文章。

您也可以在正在popup的视图控制器中进行检测

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

这对我有效

 UIViewController *fromViewController = [[[self navigationController] transitionCoordinator] viewControllerForKey:UITransitionContextFromViewControllerKey]; if (![[self.navigationController viewControllers] containsObject:fromViewController] && !self.presentedViewController) { //Something is being popped and we are being revealed } 

你特别想做什么?

如果你想检测VC1即将显示, 这个答案应该可以帮到你。 使用UINavigationControllerDelegate 。

如果你试图检测到VC2将被隐藏,那么我只会使用VC2的viewWillDisappear:

您可以为您的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]; } 

是的,在VC1中,你可以检查VC2是否被拖动.UINavigationController有一个方法viewControllers ,它将返回推入的控制器的数组,在堆栈中(意味着已经被推送)。所以你通过比较类迭代循环。如果VC2在那里,就不会有其他的匹配。 希望对你有帮助!

迅速3

 override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if self.isMovingToParentViewController { print("View is moving to ParentViewControll") } } 

我有同样的情况,但略有更具体的使用情况。 在我的情况下,我们想要确定当用户点击VC2的后退button时VC1是否出现/显示,其中VC2通过VC1在navigationController上被按下。

所以我使用了snarshad的答案帮助根据我的需要进行定制。 这里是VC1的viewDidAppearswift的代码。

 // 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") } }