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

时间:2012-09-12 03:43:42

标签: ios uinavigationcontroller stack

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

由于我试图从VC1的代码中检测到VC2的弹出,似乎 viewWillAppear viewDidAppear 之类的东西不起作用,因为这些方法每次显示VC1时都会触发,包括第一次按下它时。

编辑:我原来的问题似乎不太清楚。这是我正在尝试做的事情:确定VC1何时显示是由于VC2从堆栈顶部弹出。这是我不想做的事情:确定VC1由于被推到堆栈顶部而显示的时间。我需要某种方法来检测第一个动作但不是第二个动作。

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

10 个答案:

答案 0 :(得分:63)

iOS 5引入了两种新方法来处理这种情况。您要找的是-[UIViewController isMovingToParentViewController]。来自docs

  

<强> isMovingToParentViewController

     

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

     

- (BOOL)isMovingToParentViewController

     

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

     

讨论
  只有从内部调用时,此方法才返回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:我通过反转逻辑并且不提前返回来使示例更加明确。

答案 1 :(得分: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
}

在我的情况下,使用委托意味着拥有视图控制器&#39;行为与拥有导航堆栈的代理更紧密地结合在一起,我想要一个更独立的解决方案。这有效。

答案 2 :(得分: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];
}

关于协议和代理here的基础知识有一篇很好的文章。

答案 3 :(得分:4)

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

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

    if ([self isMovingFromParentViewController]) {
        ....
    }
}

答案 4 :(得分: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 
}

答案 5 :(得分:0)

你有什么特别的尝试?

如果您尝试检测即将显示VC1,this回答应该会对您有所帮助。使用UINavigationControllerDelegate

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

答案 6 :(得分:0)

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

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

答案 7 :(得分:0)

swift 3

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

答案 8 :(得分:0)

我得到了相同的情况,但有一些更具体的用例。就我而言 我们想确定当用户点击VC2的后退按钮时是否出现/显示VC1,其中VC2被推送到VC​​1上的navigationController上。

所以我使用snarshad's answer的帮助来根据我的需要进行定制。以下是VC1中 swift 3 viewDidAppear的代码。

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

答案 9 :(得分:-1)

您可以为您的VC2添加NSNotification的观察者,特别是JUST。

// 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];
}
相关问题