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

问题描述 投票:37回答:4

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

我想尽可能远离使用viewWillDisappearviewDidDisappear,因为我在我的项目中使用了splitview,并且在主视图中选择不同的行也将触发viewWillDisappear / viewDidDisappear方法。

ios objective-c cocoa-touch uiviewcontroller uinavigationcontroller
4个回答
79
投票

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

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

isMovingFromParentViewController

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


23
投票

更新20150430

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

选项1,示例

https://github.com/greymouser/TestNVC

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

如果我只依赖{will,did}MoveToParentViewController,我注意到在rootVC上推送第一个非rootVC时出现虚假的didMoveToParentViewController:调用,父亲!= 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]
...

我原来的答案建议单独使用{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

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

选项2

我没有探索的另一个选择是使用你的NVC sublcass,覆盖- pushViewController:animated:- popViewControllerAnimated:,并将你想要的任何行为应用于被推送的VC,或者从pop返回的VC。 (如果您尝试这样做,请务必记住在覆盖中调用super。)

更新摘要

所以,感谢phatmann有机会重新开始这个。我想我的答案现在更正确了。但是,我不太确定它是否“完全不真实”。 ;-)

原版的

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

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

输入时,willMoveToParentViewController:将被父母调用!= nil,离开时父母== nil。 didMoveToParentViewController:将永远有父!=无。

有时,viewDidDisappear可能有意义。但是,如果您真正从父容器视图控制器中寻找推送和弹出,那么上述方法就是您想要的。


0
投票

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

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

但您可以通过以下操作使用导航控制器Delegates 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*/

     }

}

希望这有帮助,祝你好运


0
投票

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

class ViewController: UIViewController {

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

此方法适用于通知协调员或其他代理人。

© www.soinside.com 2019 - 2024. All rights reserved.