双重问号,它是如何工作的?

我正在学Swift,作为这个过程的一部分,试图弄清楚这里究竟发生了什么。 我有一个自定义的segue,我想放置我的模态视图控制器解散过渡。 曾经在objective-c中的是:

UIViewController *sourceViewController = self.sourceViewController; [sourceViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil]; 

selfUIStoryboardSegue一个实例。 我在Swift中翻译了这个片段:

 self.sourceViewController.presentingViewController?.dismissViewControllerAnimated(true, completion: nil) 

从编译器得到这个错误:

“的UIViewController? 没有名为“dismissViewControllerAnimated”的成员

现在, 通过文档 , presentingViewController方法如下所示:

 var presentingViewController: UIViewController? { get } 

从我所了解的Swift语言文档中, ? 如果有的话,应该解开价值。 在这种情况下,视图控制器。 不明原因的事实是:如果我把一个双重的问号,它编译和工作:

 self.sourceViewController.presentingViewController??.dismissViewControllerAnimated(true, completion: nil) 

有人能告诉我我失踪了吗? 那该怎么办?

额外的? 需要是由于sourceViewController返回一个AnyObject而不是一个UIViewController 。 这是Objective-C的API转换中的一个缺陷(其中这种属性返回一个相当无意义的id )。 从iOS 8 beta 5开始,这仍然是一个持续的过程,显然这些API还没有被修复。

如果您提供适当的演员,它将按预期工作

 (self.sourceViewController as UIViewController).presentingViewController?.dismissViewControllerAnimated(true, completion: nil) 

现在,为什么我们需要额外的? 什么时候处理AnyObject

AnyObject可以表示任何对象types,就像Objective-C id一样。 所以在编译时你可以调用任何现有的方法,例如sourceViewController

当你这样做的时候,它会触发从AnyObjectUIViewController的隐式downcast,根据官方指南 :

与Swift中的所有向下转换一样,从AnyObject转换为更具体的对象types不保证成功,因此返回一个可选的值

所以,当你这样做

 self.sourceViewController.presentingViewController?? 

它隐含地翻译成类似的东西

  let source: UIViewController? = self.sourceViewController as? UIViewController let presenting: UIViewController? = source?.presentingViewController 

这就是为什么你需要两个? :一个用于parsingdowncast,另一个用于presentingViewController

最后,总是按照文档:

当然,如果您确定对象的types(并且知道它不是零),则可以使用as运算符强制调用。

这正是我上面提出的解决scheme。