如何正确地closures作为模式呈现的UINavigationController?

在我的TabBarViewController ,我创build了一个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

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

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

现在,如果你在MessagesViewController里面,那么它的navigationController是正在呈现的那个,这是你应该解雇的那个,但是在MessagesViewController上调用dismiss也应该工作。

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

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

要正确销毁MessagesViewController您将不得不放开navController否则将不得不popup根目录(从视图层次结构中删除MessagesViewController )。

典型的解决scheme是根本不保存对navController的引用。 展示时,您总是可以创build一个新的UINavigationController 。 另一个解决scheme是使用一个委托 – 而不是从MessagesViewController内部解雇,让它callback给主持人,这将打电话给

 self.navController.dismissViewControllerAnimated(true, completion: { self.navController = nil; }); 

尝试这个

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

不需要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.dismissViewControllerAnimated(true, completion: nil) } 

我build议你为你的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) } 

如果你只想呈现一个视图控制器,那么你可以直接展示该视图控制器,而不需要为该视图控制器设置一个导航控制器。

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

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

并从该视图控制器,你可以推到另一个视图控制器,也可以从另一个视图控制器popup。

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

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

这将成功消除messageVC并从我们提供messageVC地方回到原始视图messageVC

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

如果不确定是否显示或推送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 } 

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

 func swipedRightAndUserWantsToDismiss() { if self.isModal() == true { self.dismissViewControllerAnimated(true, completion: nil) } else { self.navigationController?.popViewControllerAnimated(true) } } 

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

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

目标C

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

迅速

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

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

 self.navigationController?.dismiss(animated: true, completion: nil)