2013-01-31 164 views
79

我有一个理论问题。现在,我们正在阅读Apple的ViewController指南。解散呈现的视图控制器

他们写道:

当谈到时间驳回呈现视图控制器,该 首选的方法是让呈现视图控制器驳回 它。换句话说,只要有可能, 呈现给视图控制器的相同视图控制器也应该对 负责解除视图控制器。虽然有几种技术用于通知 呈现视图控制器,其所呈现的视图控制器应当解除 ,但首选技术是委派。

但我无法解释,为什么我必须按照所呈现VC创建一个协议,并添加代表varible,在介绍VC解雇呈现VC创建委托方法,而不是在一个简单的通话提出视图控制器方法

[self dismissViewControllerAnimated:NO completion:nil]

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

回答

6

以我的经验,它派上用场的时候,你需要从驳回任何你想要的的ViewController并为驳斥其每个视图 - 控制执行不同的任务。任何采用该协议的viewController都可以以自己的方式解除视图。 (新iPad VS iphone,或从不同的角度解雇时,驳回时调用不同的方法传递不同的数据,等等。)

编辑:

因此,要确认一下,如果所有你想做的事就是解雇查看,我看到没有必要设置委托协议。如果你需要做不同的事情你从不同的呈现视图控制器中解雇它,这将是你最好的方式去使用委托。

+0

但如果我不需要“从不同的看法解雇时,驳回时调用不同的方法等传递不同的数据。”我可以做呈现视图控制器方法一个小电话 - - [self dismissViewControllerAnimated:NO完成:无]? – nikitahils

+0

是的,这就是我会做的。 – jhilgert00

+0

让演示者忽略呈现的视图,很明显演示者实际上已经准备好并处理返回前景:执行顺序很容易遵循,并且任何UI更新的责任都隐含地清晰。 – Johan

87

我认为苹果公司在这里稍微掩盖了他们的背影,可能会有一些API。

[self dismissViewControllerAnimated:NO completion:nil] 

实际上是一个小提琴。尽管您可以 - 合法地 - 在所呈现的视图控制器上调用此函数,但它所做的只是将消息转发给呈现视图控制器。如果你想做任何事情,只要解雇VC,你就需要知道这一点,你需要像委托方法一样对待它 - 因为这几乎就是它的原因,一个有点不灵活的委托方法。

也许他们遇到了许多不好的代码,人们并没有真正理解这是如何放在一起的,因此他们谨慎对待。

但是,当然,如果您只需要解雇这件事,那就继续吧。

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

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

[斯威夫特]

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

应该注意的是,使用'presentationViewController'基本上是无用的,因为如果'self'被嵌入到'UINavigationController'中,它将会被引用。在这种情况下,你根本无法获得'presentationViewController'。然而,'[self dismissViewControllerAnimated:completion]'仍然适用于这种情况。我的建议是继续使用,直到Apple修复它。 – memmons

+1

我喜欢这个答案在3年后仍然完全相关。 – user1021430

42

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

你的视图控制器不应该关心它是作为模式呈现,推在导航控制器上,还是其他任何东西。如果您的视图控制器自行解散,那么您认为它是以模态方式呈现的。您将无法将该视图控制器推到导航控制器上。

通过实现一个协议,你让父视图控制器决定应该如何显示/推送和取消/弹出。

0

如果您使用的是模态使用视图关闭。

[self dismissViewControllerAnimated:NO completion:nil]; 
+0

这是如何回答这个问题的:*“为什么第一选择更好?为什么苹果会推荐它?”* – jww

2

引自查看Controller Programming Guide“视图控制器如何呈现其他视图控制器”。

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

因此,一方面它使一个很好的平衡设计,良好的去耦,等...但在另一方面,这是非常实用的,因为你可以迅速得到回导航某一点。

虽然,我个人宁可使用平仓塞格斯不是试图向后遍历呈现视图控制器树,这是苹果公司关于本章当报价从会谈。

2

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

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

像,一个房租公司谁应该有权收回租金。

0

这是很多的胡扯。授权在需要时很好,但如果它使代码更加复杂 - 而且确实如此 - 则需要有一个原因。

我相信苹果有它的理由。但是,如果没有真正的理由去做这件事,那么简单地让提出的风险投资者去解决这个问题就会更清楚,更简洁,今天这里没有人提出我能看到的。

协议在需要时非常出色,但面向对象的设计永远不会让模块彼此进行不必要的通信。目标C的共同开发者Tom Love曾经评论过Objective C是“优雅”,“小”,“清晰”和“明确定义”(与C++相比)。容易他说。授权是一个有用的功能,似乎已被“过度使用”,虽然我喜欢使用该语言,但我害怕使用不必要的语法来使事情变得比事实复杂得多的想法。

+0

它可能会最初为您节省一些代码,但随着代码库的增长,您的方法会导致许多头痛。你应该理解面向对象的原则,比如分离关注点,否则你不妨将整个应用程序编码成一个大文件。 –

33

更新了斯威夫特3

我来这里只是想关闭当前(呈现)视图控制器。对于任何来到这里的人都有同样的目的,我正在给出这个答案。

导航控制器

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

返回到先前的视图控制器:

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

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

返回到根视图控制器:(。感谢this answer为目的-C)

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

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

模态视图控制器

当一个视图控制器有模式呈现,你可以通过调用

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

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

documentation说,关闭它(从第二个视图控制器),

的呈现视图控制器负责驳回查看 它呈现的控制器。如果您在所呈现的视图 控制器本身上调用此方法,UIKit会要求呈现视图控制器处理 解雇。

所以它适用于所呈现的视图控制器调用它本身。 Here就是一个完整的例子。

代表

的OP的问题是关于使用委托驳回视图的复杂性。

对于这一点我没有必要使用委托,因为我通常有一个导航控制器或模式视图控制器,但是如果我需要在未来使用the delegate pattern,我会添加更新。

5

试试这个:

[self dismissViewControllerAnimated:true completion:nil]; 
2

雨燕3.0 //辞退查看控制器在迅速

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

除了迈克尔·恩里克斯的回答,我能想到的另外一个原因,这可能是保护自己免于未确定状态的好方法:

说说ViewControllerA呈现ViewController B模态。但是,由于您可能没有编写ViewControllerA的代码,因此您不知道ViewControllerA的生命周期。在呈现视图控制器ViewControllerB之后,它可能会消除5秒(说)。在这种情况下,如果您仅仅使用ViewControllerB中的dismissViewController来解除它自己,那么您最终会处于未定义状态 - 可能不是崩溃或黑屏,而是从您的角度来看,它是一个未定义的状态。

如果您使用委托模式,那么您应该了解ViewControllerB的状态,并且可以编写一个类似于我所描述的案例的程序。

0

斯威夫特

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

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