取消呈现的视图控制器

我有一个理论上的问题。现在我正在阅读苹果的 ViewController指南。

他们写道:

当需要解除呈现的视图控制器时, 首选的方法是让呈现的视图控制器关闭 换句话说,只要有可能,同一个视图控制器 提出视图控制器也应该负责 尽管有几种技术可以通知 提出了视图控制器,它提出的视图控制器应该 被驳回,首选的技术是委托。

但是我不能解释,为什么我必须在呈现的 VC 中创建一个协议并添加委托变量,在呈现的 VC 中创建委托方法来消除呈现的 VC,而不是简单地调用 提交视图控制器方法

[self dismissViewControllerAnimated:NO completion:nil]

为什么第一选择更好? 为什么苹果公司推荐它?

158964 次浏览

根据我的经验,当您需要从 任何 ViewController 中解除它时,它会派上用场,并为解除它的每个 ViewController 执行不同的任务。任何采用该协议的 viewController 都可以以自己的方式解除视图。(ipad vs iphone,或者在从不同视图解散时传递不同的数据,在解散时调用不同的方法,等等)

编辑:

因此,澄清一下,如果您想要做的只是取消视图,那么我认为没有必要设置委托协议。如果你需要做不同的事情 < em > 在 之后你忽略它从不同的呈现视图控制器,这将是你最好的方式去使用委托。

我认为苹果公司在这里为一个可能混搭的 API 做了一些掩护。

  [self dismissViewControllerAnimated:NO completion:nil]

实际上是一个小提琴。虽然您可以合法地在呈现的视图控制器上调用它,但它所做的只是将消息转发到呈现的视图控制器。如果你想做一些仅仅忽略 VC 的事情,你需要知道这一点,并且你需要把它当作一个委托方法来对待——就像它本身一样,一个固有的不灵活的委托方法。

也许他们遇到过很多不了解如何组装的人编写的糟糕代码,因此他们很谨慎。

但是当然,如果你需要做的就是忽略这件事情,那就继续吧。

我自己的方法是一种妥协,至少它提醒了我正在发生的事情:

  [[self presentingViewController] dismissViewControllerAnimated:NO completion:nil]

[斯威夫特]

  self.presentingViewController?.dismiss(animated: false, completion:nil)

这是为了视图控制器的可重用性。

视图控制器不应该关心它是否以模态的形式出现,是否被推送到导航控制器上,或者其他什么。如果您的视图控制器解除了自身,那么您就假设它是模态显示的。您将无法将该视图控制器推送到导航控制器上。

通过实现一个协议,您可以让父视图控制器决定如何显示/推送和解除/弹出它。

如果您使用模态使用视图解散。

[self dismissViewControllerAnimated:NO completion:nil];

“视图控制器如何呈现其他视图控制器”。

所提供的视图控制器链中的每个视图控制器都具有 指向链中围绕它的其他物体 words, a presented view controller that presents another view 控制器的两个对象都是有效的 可以使用这些关系来 trace through the chain of view controllers as needed. For example, if 当用户取消当前操作时,您可以删除 通过解雇第一个提出的视图控制器的链。 忽略视图控制器不仅会忽略该视图控制器 还有它所呈现的任何视图控制器

So on one hand it makes for a nice balanced design, good de-coupling, etc... But on the other hand it's very practical, because you can quickly get back to a certain point in navigation.

Although, I personally would rather use 退出转折点 than try to traverse backwards the 呈现视图控制器 tree, which is what Apple talks about in this chapter where the quote is from.

One point is that this is a good coding approach. It satisfies many OOP principles, eg., SRP, Separation of concerns etc.

因此,呈现视图的视图控制器应该是忽略它的视图控制器。

比如,房地产公司出租房子应该有权收回房子。

真是胡扯。在需要时委托是可以的,但是如果它使代码更复杂——确实如此——那么就需要一个理由。

我相信苹果有它的理由。但是更简洁明了的是,除非有一个真正的理由,否则就让风险投资人来解雇他们,而且到目前为止,这里还没有人提出过我能看到的理由。

协议在需要的时候是非常优秀的,但是面向对象的设计从来不是让模块之间进行不必要的通信。

Tom Love (Objective C 的合作开发者)曾经评论说 Objective C 是“优雅的”、“小巧的”、“明快的”和“定义良好的”(与 C + + 相比)。他说起来容易。授权是一个有用的功能,似乎已经被过度使用“仅仅是因为”,虽然我喜欢在语言中工作,但我害怕感到有必要使用不必要的语法来使事情变得更加复杂。

Updated for Swift 3

我来这里只是想解雇当前(呈现)视图控制器。我要为任何怀着同样目的来到这里的人做出这个回答。

导航控制器

如果您使用的是导航控制器,那么它是相当容易的。

Go back to the previous view controller:

// Swift
self.navigationController?.popViewController(animated: true)


// Objective-C
[self.navigationController popViewControllerAnimated:YES];

返回根视图控制器:

// Swift
self.navigationController?.popToRootViewController(animated: true)


// Objective-C
[self.navigationController popToRootViewControllerAnimated:YES];

(感谢 这个答案的 Objective-C。)

模态视图控制器

当以模态方式显示视图控制器时,可以通过调用

// Swift
self.dismiss(animated: true, completion: nil)


// Objective-C
[self dismissViewControllerAnimated:YES completion:nil];

文件说,

呈现的视图控制器负责解除视图 如果您在呈现的视图上调用这个方法 控制器本身,UIKit 要求呈现的视图控制器处理 解雇。

因此,它的工作为目前的视图控制器调用它本身。

代表

OP 的问题是关于使用委托来取消视图的复杂性。

到目前为止,我不需要使用委托,因为我通常有一个导航控制器或模态视图控制器,但如果我需要在将来使用 委托模式,我将添加一个更新。

try this:

[self dismissViewControllerAnimated:true completion:nil];

Swift 3.0 //迅速解除视图控制器

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

除了 Michael Enriquez 的回答,我还能想到另一个原因,为什么这可能是一个保护自己免受未知状态伤害的好方法:

假设 ViewControllerA 模态地呈现 ViewControllerB。但是,由于您可能没有为 ViewControllerA 编写代码,因此不知道 ViewControllerA 的生命周期。它可能在显示视图控制器 ViewControllerB 之后解散5秒钟(比如)。

在这种情况下,如果您只是使用 ViewControllerB 中的 dismissViewController来解除自身,那么您最终将处于一种未定义的状态——从您的角度来看,可能不是崩溃或黑屏,而是一种未定义的状态。

相反,如果您使用的是委托模式,那么您将了解 ViewControllerB 的状态,并且可以为类似于我所描述的情况编程。

斯威夫特

let rootViewController:UIViewController = (UIApplication.shared.keyWindow?.rootViewController)!


if (rootViewController.presentedViewController != nil) {
rootViewController.dismiss(animated: true, completion: {
//completion block.
})
}

我喜欢这个:

        (viewController.navigationController?.presentingViewController
?? viewController.presentingViewController
?? viewController).dismiss(animated: true)

只关注问题的题目,这是正确的答案。

        presentedViewController?.dismiss(animated: true)