ios 如何检测视图控制器是否从导航控制器中弹出?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21915249/
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 23:31:57  来源:igfitidea点击:

How to detect if view controller is being popped of from the navigation controller?

iosobjective-ccocoa-touchuiviewcontrolleruinavigationcontroller

提问by aresz

I currently need to implement some code when the top view controller is being popped off from my navigation controller. Is there a way to detect when the view controller is being popped off the navigation controller stack?

当顶部视图控制器从我的导航控制器中弹出时,我目前需要实现一些代码。有没有办法检测视图控制器何时从导航控制器堆栈中弹出?

As much as possible I want to stay away from using viewWillDisappearor viewDidDisappearbecause I'm using a splitviewin my project, and selecting a different row in the master view will also trigger the viewWillDisappear/viewDidDisappearmethods.

我尽可能避免使用viewWillDisappearviewDidDisappear因为我splitview在我的项目中使用 a ,并且在主视图中选择不同的行也会触发viewWillDisappear/viewDidDisappear方法。

回答by Nishant

You can detect whether a view is being popped using the isMovingFromParentViewControllerproperty for a view controller as shown below:

您可以使用isMovingFromParentViewController视图控制器的属性检测是否正在弹出视图,如下所示:

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    if ([self isMovingFromParentViewController])
    {
        NSLog(@"View controller was popped");
    }
    else
    {
        NSLog(@"New view controller was pushed");
    }
}

isMovingFromParentViewController

Returns a Boolean value that indicates that the view controller is in the process of being removed from its parent.

isMovingFromParentViewController

返回一个布尔值,指示视图控制器正在从其父级中移除。

回答by greymouser

UPDATE 20150430

更新 20150430

Based on phatmann's feedback (first comment below), I was curious if something had changed since I answer this question over a year ago. I put together a simple, example app, and have some results that are interesting.

根据 phatmann 的反馈(下面的第一条评论),我很好奇自从我一年多前回答这个问题以来是否发生了一些变化。我整理了一个简单的示例应用程序,并得到了一些有趣的结果。

Option 1, example

选项 1,示例

https://github.com/greymouser/TestNVC

https://github.com/greymouser/TestNVC

I don't have the ability to easily test pre-8.x, so I'm not sure if something has changed since then. However, the behavior I originally described does still happen. However, thanks to puting together the test app, I did notice an oddity I didn't before.

我无法轻松测试 8.x 之前的版本,所以我不确定从那时起是否发生了一些变化。但是,我最初描述的行为仍然会发生。然而,由于将测试应用程序放在一起,我确实注意到了一个我以前没有注意到的奇怪之处。

If I just rely on {will,did}MoveToParentViewController, I noticed a spurious didMoveToParentViewController:call when pushing the first non-rootVC, on the rootVC, with parent != nil (implying it is added, not being removed). I didn't encounter this around the time of my original answer, as I usually have "permanent" rootVC's on my NVC's, and hadn't implemented the callbacks there. See the example app with logging set to LOG_WILL_DID_MTPVC(in ViewController.m). This is an -- edited for space -- snapshot of what I saw:

如果我只是依赖{will,did}MoveToParentViewController,我注意到在didMoveToParentViewController:rootVC 上推送第一个非 rootVC 时出现了一个虚假调用,父 != nil(暗示它被添加,而不是被删除)。我在最初回答时没有遇到这种情况,因为我的 NVC 上通常有“永久”rootVC,并且没有在那里实现回调。请参阅将日志记录设置为LOG_WILL_DID_MTPVC(在 ViewController.m 中)的示例应用程序。这是--为空间编辑的--我所看到的快照:

TestNVC[] -[vc(rootVC) willMoveToParentViewController [entering]
TestNVC[] -[vc(rootVC) didMoveToParentViewController [entering]
TestNVC[] -[vc(1) willMoveToParentViewController [entering]
TestNVC[] -[vc(rootVC) didMoveToParentViewController [entering]  # <-- this is odd
TestNVC[] -[vc(1) didMoveToParentViewController [entering]
...

My original answer suggested using {will,did}MoveToParentViewControlleralone, as it was a "one stop shop" to handle this behavior. However, now that I've seen the spurious call to the rootVC, I suggest a mix of {will,did}MoveToParentViewControlleras well as the standard UINavigationControllerDelegatecallbacks. For this behavior in the example app, set logging to LOG_WILL_DID_MTPVC_LEAVING_AND_NVC_WILL_DID_SHOW_VC. Now we see the following:

我最初的答案建议{will,did}MoveToParentViewController单独使用,因为它是处理这种行为的“一站式商店”。但是,既然我已经看到了对 rootVC 的虚假调用,我建议混合{will,did}MoveToParentViewController使用标准UINavigationControllerDelegate回调。对于示例应用程序中的这种行为,请将日志记录设置为LOG_WILL_DID_MTPVC_LEAVING_AND_NVC_WILL_DID_SHOW_VC。现在我们看到以下内容:

TestNVC[] -[nvcD willShowViewController]: rootVC
TestNVC[] -[nvcD didShowViewController]: rootVC
TestNVC[] -[nvcD willShowViewController]: 1
TestNVC[] -[nvcD didShowViewController]: 1
TestNVC[] -[nvcD willShowViewController]: 2
TestNVC[] -[nvcD didShowViewController]: 2
TestNVC[] -[vc(2) willMoveToParentViewController [leaving]
TestNVC[] -[nvcD willShowViewController]: 1
TestNVC[] -[vc(2) didMoveToParentViewController [leaving]
TestNVC[] -[nvcD didShowViewController]: 1
TestNVC[] -[vc(1) willMoveToParentViewController [leaving]
TestNVC[] -[nvcD willShowViewController]: rootVC
TestNVC[] -[vc(1) didMoveToParentViewController [leaving]
TestNVC[] -[nvcD didShowViewController]: rootVC

... and this makes much more sense now.

......这现在更有意义了。

Option 2

选项 2

Another option I didn't explore is using your NVC sublcass, overriding - pushViewController:animated:and - popViewControllerAnimated:, and applying whatever behaviors you want to the VC being pushed, or the VC that was returned from the pop. (Make sure to remember to call superin your overrides if you attempt this.)

我没有探索的另一个选项是使用您的 NVC 子类,覆盖- pushViewController:animated:and - popViewControllerAnimated:,并将您想要的任何行为应用于被推送的 VC 或从弹出窗口返回的 VC。(super如果您尝试这样做,请务必记住调用您的覆盖。)

Update summary

更新摘要

So, thanks to phatmann for the chance to readdress this. I think my answer is morecorrect now. However, I'm not so sure that it was ever "fully non-truthy". ;-)

所以,感谢 phatmann 有机会重新解决这个问题。我觉得我的回答现在正确了。但是,我不太确定它是否曾经“完全不真实”。;-)

ORIGINAL

原来的

If the exact behavior you described is what you are looking for, then override the following on your child view controller:

如果您所描述的确切行为正是您正在寻找的,则在您的子视图控制器上覆盖以下内容:

- (void)willMoveToParentViewController:(UIViewController *)parent;
- (void)didMoveToParentViewController:(UIViewController *)parent;

willMoveToParentViewController:will get called with parent != nil when entering, and parent == nil when leaving. didMoveToParentViewController:will always have parent != nil.

willMoveToParentViewController:进入时会被调用 parent != nil ,离开时 parent == nil 。didMoveToParentViewController:将始终有 parent != nil。

Sometimes, viewDidDisappearmay make sense. However, if you're truly looking for push and pop from the parent container view controller, those methods above are what you want.

有时,viewDidDisappear可能是有道理的。但是,如果您真的要从父容器视图控制器中寻找 push 和 pop,那么上面的那些方法就是您想要的。

回答by Eneko Alonso

If you don't need to know before the view controller is removed, and just need to know it has been popped, you can also use deinit.

如果在移除视图控制器之前不需要知道,只需要知道它已被弹出,也可以使用deinit.

class ViewController: UIViewController {

    deinit {
        // View controller has been popped/dismissed and it's being released
    }
}

This method works well to notify coordinators or other delegates.

这种方法可以很好地通知协调员或其他代表。

回答by David.Chu.ca

My experience with iOS 13 is that the property value of isMovingFromParentis not always consistent. When you have search controller being in active mode (search text field is tapped), back to parent view will have falsevalue for this property.

我对 iOS 13 的体验是 的属性值isMovingFromParent并不总是一致的。当您的搜索控制器处于活动模式时(点击搜索文本字段),返回父视图将具有false此属性的值。

Here is my way to determine if a view is from parent or not:

这是我确定视图是否来自父级的方法:

class MyBaseViewController: UIViewController {
    private var _isPushedToAnotherView = false
    var isPushedToAnotherView: Bool {
      return _isPushedToAnotherView
    }
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
      super.prepare(for: segue, sender: sender)
      ...
      _isPushedToAnotherView = true
    }
    override func viewWillAppear(_ animated: Bool) {
      super.viewWillAppear(animated)
      ...
      _isPushedToAnotherView = false
    }
    ...
}

class MyExtendedClass: MyBaseViewController {
  ...
  override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    ...
    if !isPushedToAnotherView {
        // clear resources hold by this class
    }
}

回答by MhmdRizk

For Swift Users (Swift 3 - 4.2):

对于 Swift 用户 (Swift 3 - 4.2):

I wanted to detect when the view controller is being popped from the stack, so I wasn't able to use viewWillDisappearor viewDidDisappearcallbacks, since these callbacks will be called when the view controller is not visible anymore, and not when it's popped from the stack.

我想检测视图控制器何时从堆栈中弹出,因此我无法使用viewWillDisappearviewDidDisappear回调,因为当视图控制器不再可见时将调用这些回调,而不是从堆栈中弹出时调用。

but you can use the navigation controller Delegates UINavigationControllerDelegateby doing the below:

但是您可以UINavigationControllerDelegate通过执行以下操作来使用导航控制器委托:

let your controller conform to UINavigationControllerDelegate:

让您的控制器符合UINavigationControllerDelegate

class ViewController : UIViewController {

      override func viewDidLoad() {
          super.viewDidLoad()
          self.navigationController?.delegate = self
      }

}




extension ViewController : UINavigationControllerDelegate {

     override func willMove(toParentViewController parent: UIViewController?) {

     /*You can detect here when the viewcontroller is being popped*/

     }

}

hope this helps, goodluck

希望这有帮助,祝你好运