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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12380905/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 20:03:23  来源:igfitidea点击:

iOS how to detect programmatically when top view controller is popped?

iosuinavigationcontrollerstack

提问by JMLdev

Suppose I have a nav controller stack with 2 view controllers: VC2 is on top and VC1 is underneath. Is there code I can include in VC1 that will detect that VC2 has just been popped off the stack?

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

Since I'm trying to detect the popping of VC2 from within the code for VC1 it seems that something like viewWillAppearor viewDidAppearwon't work, because those methods fire every time VC1 is displayed, including when it is first pushed on the stack.

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

EDIT:it seems I was not very clear with my original question. Here's what I'm trying to do: determine when VC1 is being shown due to VC2 being popped off the top of the stack. Here's what I'm NOT trying to do: determine when VC1 is being shown due to being pushed onto the top of the stack. I need some way that will detect the first action but NOT the second action.

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

Note: I don't particularly care about VC2, it can be any number of other VCs that get popped off the stack, what I do care about is when VC1 becomes the top of the stack again due to some other VC begin popped off the top.

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

回答by Ryder Mackay

iOS 5 introduced two new methods to handle exactly this type of situation. What you're looking for is -[UIViewController isMovingToParentViewController]. From the docs:

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

isMovingToParentViewController

Returns a Boolean value that indicates that the view controller is in the process of being added to a parent.

- (BOOL)isMovingToParentViewController

Return Value
YES if the view controller is appearing because it was added as a child of a container view controller, otherwise NO.

Discussion
This method returns YES only when called from inside the following methods:

-viewWillAppear:
-viewDidAppear:

isMovingToParentViewController

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

- (BOOL)isMovingToParentViewController

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

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

-viewWillAppear:
-viewDidAppear:

In your case you could implement -viewWillAppear:like so:

在您的情况下,您可以-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
    }
}

EDIT:There's a subtle semantic difference to consider here—are you interested in the fact that VC2 in particular popped off the stack, or do you want to be notified each time VC1 is revealed as a result of anycontroller popping? In the former case, delegation is a better solution. A straight-up weak reference to VC1 could also work if you never intend on reusing VC2.

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

EDIT 2:I made the example more explicit by inverting the logic and not returning early.

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

回答by snarshad

isMovingTo/FromParentViewController won't work for pushing and popping into a navigation controller stack.

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

Here's a reliable way to do it (without using the delegate), but it's probably iOS 7+ only.

这是一种可靠的方法(不使用委托),但可能仅适用于 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
}

In my case, using the delegate would mean having the view controllers' behavior be more tightly coupled with the delegate that owns the nav stack, and I wanted a more standalone solution. This works.

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

回答by Brad Eaton

One way you could approach this would be to declare a delegate protocol for VC2 something like this:

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

in VC1.h

在 VC1.h

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

in VC1.m

在 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
}

in VC2.h

在 VC2.h

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

@interface VC2 : UIViewController {

    id<VC2Delegate> delegate;
}

@property (nonatomic, assign) id delegate;

...

@end

VC2.m

VC2.m

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

There's a good article on the basics of protocols and delegates here.

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

回答by Saren Inden

You can also detect in the view controller that is being popped

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

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

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

回答by chuanfeng

This is worked for me

这对我有用

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

回答by BLC

I got the same situation but with slight more specific use case. In my case we wanted to determine if a VC1 is appeared/displayed when user tap on VC2's back button where VC2 is pushed on navigationController over VC1.

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

So I used help of snarshad's answerto customised as per my need. Here is the code in VC1's viewDidAppearin swift 3.

所以我使用了snarshad 的帮助来根据我的需要进行定制。这里是VC1的代码viewDidAppear迅速3

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

回答by iParesh

swift 3

迅捷 3

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

回答by iParesh

What are you specifically trying to do?

你特别想做什么?

If you're trying to detect that VC1 is about to be shown, thisanswer should help you. Use UINavigationControllerDelegate.

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

If you're trying to detect that VC2 is about to be hidden, I would just use the viewWillDisappear:of VC2.

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

回答by Zhang

You can add an observer for NSNotification specifically JUST for your VC2.

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

Now in in your VC2's view will disappear, you can post a notification:

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

-(void)viewWillDisappear
{
    [[NSNotificationCenter defaultCenter] postNotificationNamed:@"notif_dismissingVC2" object:nil];
}

回答by Sandy

Yes, in VC1you can check whether VC2is popped or not. UINavigationController there is one method viewControllerswhich will returns the array of pushed Controllers, which are in the stack (i.e. which have been pushed).

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

So you iterate through loop by comparing class. If VC2is there, will have match, otherwise not.

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