如何正确关闭作为模式呈现的 UINavigationController?
Posted
技术标签:
【中文标题】如何正确关闭作为模式呈现的 UINavigationController?【英文标题】:How to correctly dismiss a UINavigationController that's presented as a modal? 【发布时间】:2016-02-15 18:28:24 【问题描述】:在我的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
【问题讨论】:
【参考方案1】:您的控制器层次结构如下所示:
UITabViewController
|
| presents
|
UINavigationController
|
| contains view controllers
|
[root, MessagesViewController]
现在,如果你在 MessagesViewController
内部,那么它的 navigationController
就是正在呈现的那个,这就是你应该解雇的那个,但是在 MessagesViewController
上调用 dismiss
也应该可以工作。
但是,问题在于解除导航控制器不会删除其视图控制器。看来您正握着导航控制器(因为您使用 self.navController
呈现它)所以状态将变为
UITabViewController
|
| self.navController holds a reference to
|
UINavigationController
|
| contains view controllers
|
[root, MessagesViewController]
要正确销毁MessagesViewController
,您必须要么放开navController
,要么必须弹出到根目录(从而从视图层次结构中删除MessagesViewController
)。
典型的解决方案是根本不保存对navController
的引用。您可以在演示时创建一个新的UINavigationController
。
另一种解决方案是使用委托 - 而不是从 MessagesViewController
内部解散,而是让它回调到演示者,后者将调用
self.navController.dismiss(animated: true)
self.navController = nil
【讨论】:
谢谢。如果我在堆栈中有许多视图控制器,但我的委托调用dismissViewControllerAnimated
然后将其设置为 nil ,它会取消 所有 堆栈中的视图控制器吗?
当你放弃对navController
的所有引用时,如果你不在其他地方持有它们,它的所有视图控制器都将被销毁。
您也无法关闭已设置为 rootviewcontroller 的视图控制器。所以,如果:【参考方案2】:
试试这个
func swipedRightAndUserWantsToDismiss()
self.navigationController.dismissViewControllerAnimated(false, completion:nil);
【讨论】:
【参考方案3】:您可以使用以下方法正确关闭在 Swift 4 中显示为模式的 UINavigationController
:
self.navigationController?.popViewController(animated: true)
【讨论】:
【参考方案4】:如果您只想呈现一个视图控制器,那么您可以直接呈现该视图控制器,而无需为该特定视图控制器获取导航控制器。
但是当我们需要从显示的视图控制器导航时,我们需要将视图控制器作为导航控制器的根视图。这样我们就可以从显示的视图控制器中导航。
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)
【讨论】:
【参考方案5】:不需要拥有 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)
【讨论】:
【参考方案6】:我建议你为你的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)
【讨论】:
【参考方案7】:这就是我在 Objective C 中解决问题的方法。
您可以在 self.navigationController 本身上调用 dismissViewControllerAnimated:NO。
目标 C
[self.navigationController dismissViewControllerAnimated:NO completion:nil];
斯威夫特
self.navigationController.dismissViewControllerAnimated(false, completion: nil)
【讨论】:
【参考方案8】:在 Swift 3 中,这是通过以下方式实现的:
self.navigationController?.dismiss(animated: true, completion: nil)
【讨论】:
以上是关于如何正确关闭作为模式呈现的 UINavigationController?的主要内容,如果未能解决你的问题,请参考以下文章