消除呈现的视图控制器


116

我有一个理论上的问题。现在,©正在阅读Apple的ViewController指南。

他们写:

当需要解散呈现的视图控制器时,首选方法是让呈现的视图控制器将其解雇。换句话说,只要有可能,呈现视图控制器的同一视图控制器也应负责解散它。尽管有多种技术可以通知呈现视图控制器其呈现的视图控制器应被取消,但首选技术是委派。

但是我无法解释,为什么我必须在演示的VC中创建一个协议并添加委托变量,在演示的VC中创建委托方法以消除演示的VC,而不是在演示的视图控制器方法中进行简单的调用

[self dismissViewControllerAnimated:NO completion:nil]

为什么首选更好?苹果为什么推荐它?

Answers:


122

我认为,Apple在这里为一块可能很混乱的API稍加掩饰。

  [self dismissViewControllerAnimated:NO completion:nil]

实际上是一个小提琴。尽管您可以-在合法的情况下-在呈现的视图控制器上调用它,但是它所做的只是将消息转发到呈现的视图控制器上。如果您想做的只是关闭VC,那么您将需要了解这一点,并且需要将它与委托方法一样对待-因为这几乎是什么,所以烘焙有点不灵活委托方法。

也许他们遇到了一些不好的代码,因为人们并不真正了解它们的组合方式,因此请谨慎行事。

但是,当然,如果您需要做的只是解开该问题,请继续。

我自己的方法是一种折衷方案,至少它使我想起发生了什么事:

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

[迅速]

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

26
应当指出,使用presentingViewController几乎是无用的,因为它将引用UINavigationControllerif self嵌入其中。在这种情况下,您将一无所获presentingViewController。但是,[self dismissViewControllerAnimated:completion]在这种情况下仍然有效。我的建议是继续使用它,直到Apple修复它为止。
记忆

4
我喜欢这个答案在3年后仍然完全有意义。
user1021430 '17

1
其他需要考虑的是视图控制器不知道它的显示方式。它可能已经被呈现,被推到导航控制器,选项卡栏控制器的一部分等上。使用委托可以使用与呈现任何视图方法相反的方法,使“呈现”视图控制器“关闭”视图控制器。
大卫·史密斯

51

为Swift 3更新

我来到这里只是想消除当前的(显示的)视图控制器。我正在为有相同目的来到这里的任何人提供这个答案。

导航控制器

如果您使用的是导航控制器,则非常简单。

返回上一个视图控制器:

// 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的回答。)

模态视图控制器

模态显示View Controller时,您可以通过调用将其从第二个View Controller中消除

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

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

文件说,

呈现视图控制器负责解散其呈现的视图控制器。如果您在呈现的视图控制器本身上调用此方法,则UIKit会要求呈现的视图控制器处理撤消。

因此,它可以使呈现的视图控制器自行调用它。是一个完整的例子。

代表们

OP的问题在于使用委托来消除视图的复杂性。

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


50

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

您的视图控制器应该不在乎它是作为模态呈现,被推到导航控制器上还是其他形式。如果您的视图控制器自行关闭,则假定它是以模态显示的。您将无法将该视图控制器推到导航控制器上。

通过实现协议,您可以让父视图控制器决定如何呈现/推送和关闭/弹出它。



6

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

编辑:

因此,澄清一下,如果您只想关闭视图,则无需设置委托协议。如果您需要从不同的呈现视图控制器中解散它之后需要做不同的事情,那将是使用委托的最佳方法。


但是,如果我不需要“从不同视图关闭时传递不同的数据,在关闭视图时调用不同的方法,等等。”我可以在呈现的视图控制器方法中做一个小的调用吗?[self dismissViewControllerAnimated:NOcomplete:nil]?
nikitahils

让演示者退出显示的视图,很明显,演示者实际上已经准备好并且正在处理返回到前台的问题:执行顺序很容易遵循,并且任何UI更新的职责都非常明确。
约翰

2

引用《 View Controller编程指南》“ View Controller如何呈现其他View Controller”。

呈现的视图控制器链中的每个视图控制器都具有指向链中围绕它的其他对象的指针。换句话说,呈现另一个视图控制器的呈现视图控制器在其presentingViewController和presentedViewController属性中均具有有效对象。您可以根据需要使用这些关系来跟踪视图控制器链。例如,如果用户取消当前操作,则可以通过关闭显示的第一个视图控制器来删除链中的所有对象。消除视图控制器不仅消除了该视图控制器,还消除了它提供的任何视图控制器。

因此,一方面可以实现良好的平衡设计,良好的去耦等。但是另一方面,它非常实用,因为您可以快速回到导航的特定点。

虽然,我个人宁愿使用轻松的顺序,也不希望向后遍历呈现的视图控制器树,这就是苹果在本章中引用的地方。


2

有一点是,这是一种很好的编码方法。它满足许多OOP原则,例如SRP,关注点分离等。

因此,呈现视图的视图控制器应该是关闭视图的控制器。

就像,一家房地产公司在出租房屋时,应有权将其收回。


2

Swift 3.0 //迅速关闭视图控制器

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

1

除了迈克尔·恩里克斯(Michael Enriquez)的答案,我还能想到另一个原因,为什么这可能是一种保护自己不受不确定状态影响的好方法:

假设ViewControllerA以模态形式显示ViewControllerB。但是,由于您可能尚未编写ViewControllerA的代码,因此您不了解ViewControllerA的生命周期。在展示您的视图控制器ViewControllerB之后,可能需要5秒钟(例如)。

在这种情况下,如果仅使用dismissViewControllerViewControllerB来关闭自身,则最终将处于不确定状态-从您的角度来看,可能不是崩溃或黑屏,而是不确定状态。

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


1

迅速

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

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

0

如果使用模态,请使用视图关闭。

[self dismissViewControllerAnimated:NO completion:nil];

这如何回答以下问题:“为什么首选更好?Apple为什么推荐它?”
jww

0

这是很多鲍尼。委托在需要时很好,但是如果使代码更复杂(确实如此),那么就需要这样做的原因。

我确定苹果有其原因。但是,除非有确凿的理由这样做,否则简单地让提出的VC撤职就更清楚,更简洁了,到目前为止,这里没有人提出我所看到的。

协议在需要时非常出色,但是面向对象的设计绝不需要模块之间进行不必要的通信。

Tom Love(Objective C的共同开发者)曾经评论说,Objective C是“优雅”,“小”,“酥脆”和“定义明确”的(与C ++相比)。他很容易说。委派是一个有用的功能,似乎只是因为“过度使用”而已被过度使用,而当我喜欢用这种语言工作时,我害怕被砍伐的想法被迫使用不必要的语法来使事情变得比必须的复杂。


最初可能会为您节省一些代码,但是随着代码库的增加,您的方法将导致许多麻烦。您应该了解面向对象的原则,例如关注点分离,否则您最好将整个应用程序编码到一个大文件中。
Werner Altewischer

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.