为啥在 UINavigationController 上关闭 UIAlertController 调用关闭?
Posted
技术标签:
【中文标题】为啥在 UINavigationController 上关闭 UIAlertController 调用关闭?【英文标题】:Why dismissing a UIAlertController calls dismiss on UINavigationController?为什么在 UINavigationController 上关闭 UIAlertController 调用关闭? 【发布时间】:2018-12-21 13:13:20 【问题描述】:我试图理解为什么当从导航中显示的视图控制器中关闭 UIAlertController 时,会调用 UINavigationController 上的 dimiss(animetaded:)
。
原因是我从 UINavigationController 继承了一些逻辑,以便在导航被解除时添加一些逻辑,但每次解除警报时都会无意中调用它。
据我了解,presentingViewController 负责关闭呈现的控制器,但这里似乎并非如此。
我错过了什么?
要重现,请运行下面的代码,它将记录消息“DISMISS ON NAVIGATION”。
class RootViewController: UIViewController
override func viewDidAppear(_ animated: Bool)
super.viewDidAppear(animated)
let alert = UIAlertController(title: "", message: "", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: nil))
present(alert, animated: true)
class Nav: UINavigationController
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil)
print("DISMISS ON NAVIGATION")
super.dismiss(animated: flag, completion: nil)
现在从任何地方展示导航控制器。
let contrl = RootViewController()
contrl.view.backgroundColor = .red
contrl.definesPresentationContext = true
let nav = Nav(rootViewController: contrl)
present(nav, animated: true, completion: nil)
编辑:更新代码以使 RootViewController 定义演示上下文。 Edit2:更新代码以更好地表示场景。
【问题讨论】:
【参考方案1】:原因是导航控制器是显示警报控制器的控制器,即使您在视图控制器上调用present
。 dismiss
呼叫也是如此。
如果您希望视图控制器显示警报,请将其 definesPresentationContext
属性设置为 true
。
见https://developer.apple.com/documentation/uikit/uiviewcontroller/1621380-present...
您调用此方法的对象可能并不总是那个对象 处理演示文稿。每种演示风格都有不同的 支配其行为的规则。例如,全屏演示 必须由一个视图控制器来制作,该控制器本身覆盖整个 屏幕。如果当前视图控制器无法满足请求, 它将请求向上转发视图控制器层次结构到它的 最近的父级,然后可以处理或转发请求。
...和https://developer.apple.com/documentation/uikit/uiviewcontroller/1621456-definespresentationcontext:
当使用 UIModalPresentationStyle.currentContext 或 UIModalPresentationStyle.overCurrentContext 样式来呈现一个视图 控制器,此属性控制现有的视图控制器在 您的视图控制器层次结构实际上已被新内容覆盖。 当基于上下文的演示发生时,UIKit 从 呈现视图控制器并向上走视图控制器层次结构。 如果它找到了一个该属性的值为真的视图控制器, 它要求视图控制器呈现新的视图控制器。如果不 视图控制器定义表示上下文,UIKit 要求 窗口的根视图控制器来处理演示。 此属性的默认值为 false。一些系统提供的视图控制器,比如 UINavigationController,改变了默认值 值为真。
更新:
对于您的具体问题(如果我理解正确的话)也许是保持演示逻辑不变(导航控制器呈现)的最佳解决方案,而是在导航控制器的解除方法中添加一个检查:
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil)
if !(presentedViewController is UIAlertController)
// your additional logic
super.dismiss(animated: flag, completion: completion)
【讨论】:
有道理,但即使在更新代码(见问题编辑)之后,行为也是一样的。在导航上调用关闭。 我对你的视图层次结构有点困惑......你能解释一下它是什么样的吗?有一个Nav
导航控制器包含RootViewController
vc?那么ViewController
类呢?除此之外,您必须为 呈现 的视图控制器将 definesPresentationContext
设置为 true
。不是呈现的。
它是一个以 RootViewController 为根的 UINavigationController。 RootViewController 表示 UIAlertController。这里的 ViewController 可以是任何呈现导航的控制器。将更新解码代码以更好地表示它。
@MarcelodeAguiar 更新了我的答案。
尽管这解决了眼前的问题,但它并不能解释为什么会出现这种不稳定的行为,所以我还没有将其标记为答案。谢谢。以上是关于为啥在 UINavigationController 上关闭 UIAlertController 调用关闭?的主要内容,如果未能解决你的问题,请参考以下文章
在 UINavigationController 中设置时图像不显示
将 managedObjectContext 发送到 viewController 崩溃
如何正确关闭作为模式呈现的 UINavigationController?
ID:[...] 的 NSManagedObject 已失效