124

I have a theoretic question. Now İ'm reading Apple's ViewController guide.

They wrote:

When it comes time to dismiss a presented view controller, the preferred approach is to let the presenting view controller dismiss it. In other words, whenever possible, the same view controller that presented the view controller should also take responsibility for dismissing it. Although there are several techniques for notifying the presenting view controller that its presented view controller should be dismissed, the preferred technique is delegation.

But I can't explain, why I have to create a protocol in presented VC and add delegate varible, create delegate method in presenting VC for dismissing presented VC, instead of a simple call in presented view controller method

[self dismissViewControllerAnimated:NO completion:nil]?

Why is the first choice better? Why does Apple recommend it?

4

14 回答 14

133

我认为 Apple 正在为一个可能很笨拙的 API 掩饰一下。

  [self dismissViewControllerAnimated:NO completion:nil]

其实有点小题大做。尽管您可以合法地在呈现的视图控制器上调用它,但它所做的只是将消息转发到呈现的视图控制器。如果您想在关闭 VC 之外做任何事情,您将需要知道这一点,并且您需要以与委托方法相同的方式对待它 - 因为这几乎就是它的本质,一个烘焙的有点不灵活委托方法。

也许他们遇到了很多糟糕的代码,这些代码并不真正了解这些代码是如何组合在一起的,因此他们很谨慎。

但是,当然,如果您需要做的就是忽略这件事,请继续。

我自己的做法是一种妥协,至少它提醒了我是怎么回事:

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

[迅速]

  self.presentingViewController?.dismiss(animated: false, completion:nil)
于 2013-01-31T23:29:22.513 回答
58

为 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的这个答案。)

模态视图控制器

当视图控制器以模态方式呈现时,您可以通过调用将其关闭(从第二个视图控制器)

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

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

文件说,

呈现视图控制器负责关闭它呈现的视图控制器。如果您在呈现的视图控制器本身上调用此方法,UIKit 会要求呈现的视图控制器处理解除。

所以它适用于呈现的视图控制器自己调用它。是一个完整的例子。

代表们

OP 的问题是关于使用代表解除视图的复杂性。

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

于 2016-06-10T04:36:17.467 回答
54

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

您的视图控制器不应该关心它是否被呈现为模式、推送到导航控制器或其他任何东西。如果您的视图控制器自行关闭,那么您假设它是以模态方式呈现的。您将无法将该视图控制器推送到导航控制器上。

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

于 2014-07-11T03:19:15.927 回答
7

尝试这个:

[self dismissViewControllerAnimated:true completion:nil];
于 2017-02-28T09:54:39.260 回答
6

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

编辑:

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

于 2013-01-31T23:17:35.950 回答
3

Swift 3.0 //在swift中关闭视图控制器

self.navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
于 2017-05-20T10:31:42.540 回答
2

引用视图控制器编程指南,“视图控制器如何呈现其他视图控制器”。

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

所以一方面它实现了一个很好的平衡设计,良好的解耦等等......但另一方面它非常实用,因为你可以快速回到导航的某个点。

虽然,我个人更愿意使用展开转场而不是尝试向后遍历呈现的视图控制器树,这就是苹果在本章中引用的内容。

于 2015-03-03T06:06:16.673 回答
2

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

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

例如,出租房屋的房地产公司应该有权收回房屋。

于 2015-05-14T09:33:47.430 回答
1

我喜欢这个:

        (viewController.navigationController?.presentingViewController
            ?? viewController.presentingViewController
            ?? viewController).dismiss(animated: true)
于 2020-10-21T11:00:47.827 回答
1

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

假设 ViewControllerA 以模态方式呈现 ViewControllerB。但是,由于您可能没有为 ViewControllerA 编写代码,因此您不知道 ViewControllerA 的生命周期。在呈现您的视图控制器 ViewControllerB 后,它可能会关闭 5 秒(例如)。

在这种情况下,如果您只是简单地使用dismissViewControllerfrom ViewControllerB 来关闭自己,您最终会处于未定义的状态——从您的角度来看,可能不是崩溃或黑屏,而是未定义的状态。

相反,如果您使用的是委托模式,您会知道 ViewControllerB 的状态,并且可以针对我描述的情况进行编程。

于 2017-06-13T08:41:15.803 回答
1

迅速

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

        if (rootViewController.presentedViewController != nil) {
            rootViewController.dismiss(animated: true, completion: {
                //completion block.
            })
        }
于 2017-10-31T12:51:19.770 回答
0

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

[self dismissViewControllerAnimated:NO completion:nil];
于 2014-12-16T16:28:06.683 回答
0

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

        presentedViewController?.dismiss(animated: true)
于 2021-12-02T22:00:20.210 回答
0

这是胡说八道。委托在需要时很好,但如果它使代码更复杂——确实如此——那么就需要有它的理由。

我相信苹果有它的理由。但是,除非有真正的理由不这样做,而且到目前为止,这里没有人提出我能看到的,否则简单地让所介绍的 VC 进行解雇会更清晰、更简洁。

协议在需要时非常出色,但面向对象的设计绝不是让模块不必要地相互通信。

Tom Love(Objective C 的共同开发者)曾经评论说,Objective C 是“优雅的”、“小巧的”、“清晰的”和“定义明确的”(与 C++ 相比)。他说得轻松。委托是一个有用的功能,似乎“仅仅因为”而被过度使用,虽然我喜欢使用该语言工作,但我害怕感觉被迫使用不必要的语法来使事情变得比它们必须的更复杂的想法。

于 2016-02-05T02:56:53.500 回答