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

TIM*_*MEX 27 objective-c ios 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)
Run Code Online (Sandbox Code Playgroud)

在我的内心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")
}
Run Code Online (Sandbox Code Playgroud)

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

Sul*_*han 26

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

UITabViewController
    |
    | presents
    |
UINavigationController
    |
    | contains view controllers
    |
[root, MessagesViewController]
Run Code Online (Sandbox Code Playgroud)

现在,如果你在里面MessagesViewController,那么它navigationController是正在呈现的一个,这就是你应该驳回之一,但呼吁dismissMessagesViewController应该工作了.

但是,问题是解雇导航控制器不会删除其视图控制器.看起来你正在坚持你的导航控制器(因为你正在使用它self.navController),所以状态将成为

UITabViewController
    |
    | self.navController holds a reference to
    |
UINavigationController
    |
    | contains view controllers
    |
[root, MessagesViewController]
Run Code Online (Sandbox Code Playgroud)

要正确销毁,MessagesViewController您必须放弃navController或者必须弹出到root(从而MessagesViewController从视图层次结构中删除).

典型的解决方案是根本不保存引用navController.你总是可以UINavigationController在展示时创建一个新的.另一个解决方案是使用委托 - 而不是从内部解雇MessagesViewController,让它回拨给演示者,它会调用

self.navController.dismiss(animated: true) {
     self.navController = nil
}
Run Code Online (Sandbox Code Playgroud)


She*_*Ali 10

试试这个

func swipedRightAndUserWantsToDismiss(){
    self.navigationController.dismissViewControllerAnimated(false, completion:nil);
}
Run Code Online (Sandbox Code Playgroud)


Far*_*ris 7

您可以使用以下内容正确关闭UINavigationController在 Swift 4 中显示为模态的 a:

self.navigationController?.popViewController(animated: true)
Run Code Online (Sandbox Code Playgroud)


Max*_*Max 5

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

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

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

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

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

func swipedRightAndUserWantsToDismiss() {
  self.dismiss(animated: true, completion: nil)
}
Run Code Online (Sandbox Code Playgroud)

这将messageVC成功解散,并从我们提出的地方回到原点viewcontroller messageVC.

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

如果您不确定是否呈现或推送了messageVC,那么您可以通过此答案进行检查.

而快速版本检查是

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
}
Run Code Online (Sandbox Code Playgroud)

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

func swipedRightAndUserWantsToDismiss() {

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

        }
Run Code Online (Sandbox Code Playgroud)