如何正确解雇一个呈现为模态的UINavigationController?

时间:2016-02-15 18:28:25

标签: ios objective-c swift

在我的TabBarViewController中,我创建了一个UINavigationController并将其作为模态呈现。

var navController =  UINavigationController()
let messageVC = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
self.presentViewController(self.navController, animated: false, completion: nil)
self.navController.pushViewController(messageVC, animated: false)

MessageViewController内,我想解雇它:

func swipedRightAndUserWantsToDismiss(){
    if self == self.navigationController?.viewControllers[0] {
        self.dismissViewControllerAnimated(true, completion: nil) //doesn't deinit
    }else{
        self.navigationController?.popViewControllerAnimated(true) //deinits correctly
    }
}

deinit{
    print("Deinit MessagesViewController")
}

问题在于,当我到达根视图控制器并尝试关闭子视图和UINavigationController时,我的MessagesViewController deinit不会被调用。有些东西正在坚持下去 - 很可能是UINavigationController

8 个答案:

答案 0 :(得分:23)

您的控制器层次结构如下所示:

UITabViewController
    |
    | presents
    |
UINavigationController
    |
    | contains view controllers
    |
[root, MessagesViewController]

现在,如果你在MessagesViewController内,那么它的navigationController就是正在呈现的那个,那就是你应该解雇的那个,但在dismiss上呼叫MessagesViewController也应该工作。

然而,问题是解雇导航控制器不会删除其视图控制器。您似乎正在使用导航控制器(因为您使用self.navController呈现它)因此状态将变为

UITabViewController
    |
    | self.navController holds a reference to
    |
UINavigationController
    |
    | contains view controllers
    |
[root, MessagesViewController]

要正确销毁MessagesViewController,您必须放弃navController,否则您必须弹出到root(从而从视图层次中移除MessagesViewController)。

典型的解决方案是不要保存对navController的引用。您可以在演示时始终创建新的UINavigationController。 另一个解决方案是使用委托 - 而不是从MessagesViewController内部解雇,让它回调给演示者,这将调用

self.navController.dismiss(animated: true) {
     self.navController = nil
}

答案 1 :(得分:9)

试试这个

func swipedRightAndUserWantsToDismiss(){
    self.navigationController.dismissViewControllerAnimated(false, completion:nil);
}

答案 2 :(得分:5)

如果你想只呈现一个viewcontroller,那么你可以直接呈现那个viewcontroller,而不需要为那个特定的viewcontroller带一个导航控制器。

但是当我们需要从那个呈现的视图控制器导航时,我们需要将视图控制器作为导航控制器的根视图。这样我们就可以从那个呈现的视图控制器中导航。

let messageVC = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
let MynavController = UINavigationController(rootViewController: messageVC)
self.presentViewController(MynavController, animated: true, completion: nil)

从该呈现的视图控制器,您可以推送到另一个视图控制器,并从另一个视图控制器弹出。

从呈现的视图控制器,这里messageVC,我们不得不将其视为

func swipedRightAndUserWantsToDismiss() {
  self.dismiss(animated: true, completion: nil)
}

将成功解除messageVC并从我们提交messageVC的位置返回到原始视图控制器。

这是使用导航控制器执行presentViewController的正确流程,以继续在视图控制器之间导航。

如果您不确定是否展示或推送了messageVC,那么您可以查看by this answer

要检查的快速版本是

func isModal() -> Bool {
    if((self.presentingViewController) != nil) {
        return true
    }

    if(self.presentingViewController?.presentedViewController == self) {
        return true
    }

    if(self.navigationController?.presentingViewController?.presentedViewController == self.navigationController) {
        return true
    }

    if((self.tabBarController?.presentingViewController?.isKindOfClass(UITabBarController)) != nil) {
        return true
    }

    return false
}

所以我们解雇的最后行动就像是

func swipedRightAndUserWantsToDismiss() {

            if self.isModal() == true {
                self.dismiss(animated: true, completion: nil)
            }
            else {
                self.navigationController?.popViewControllerAnimated(true)
            }

        }

答案 3 :(得分:4)

无需拥有navController的成员。使用以下代码显示您的MessagesViewController。

let messageVC = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
let pesentingNavigationController = UINavigationController(rootViewController: messageVC)
self.presentViewController(pesentingNavigationController, animated: true, completion: nil)

你的解雇视图控制器代码将是

func swipedRightAndUserWantsToDismiss() {
  self.navigationController.dismiss(animated: true, completion: nil)
}

答案 4 :(得分:3)

在Swift 3中,这是通过以下方式实现的:

sdl00999  2.6.32.54-0.7.TDC.1.R.4-default  #1 SMP 2012-04-19 16:07:40 +0200  x86_64  2016/11/15

-------------------------- analysis date: 2016/11/15 --------------------------
20:39:37  memtotal memfree buffers cached dirty slabmem  swptotal swpfree _mem_

20:39:41     3700M   2386M      9M   353M    0M    121M      309M    302M
20:39:43     3700M   2385M      9M   353M    0M    121M      309M    302M
20:39:47     3700M   2385M      9M   353M    2M    121M      309M    302M
20:39:49     3700M   2385M      9M   353M    2M    121M      309M    302M

答案 5 :(得分:2)

我建议您为UINavigationController使用其他初始化程序:

let messageVC = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
let navController = UINavigationController(rootViewController: messageVC)
self.presentViewController(self.navController, animated: true, completion: nil)

要干扰,只需做

func swipedRightAndUserWantsToDismiss() {
  self.navigationController.dismissViewControllerAnimated(true, completion: nil)
}

答案 6 :(得分:2)

这就是我在Objective C中解决问题的方法。

您可以在 self.navigationController 本身上调用 dismissViewControllerAnimated:NO

目标C

[self.navigationController dismissViewControllerAnimated:NO completion:nil];

<强>夫特

self.navigationController.dismissViewControllerAnimated(false, completion: nil)

答案 7 :(得分:1)

您可以使用以下命令正确消除在Swift 4中以模态形式显示的UINavigationController

self.navigationController?.popViewController(animated: true)