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

时间:2014-09-22 18:15:10

标签: ios uiviewcontroller swift

我正在学习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'

现在,by documentationpresentingViewController方法如下所示:

var presentingViewController: UIViewController? { get }

根据我对Swift语言文档的理解,?应解包该值,如果有的话。在这种情况下,视图控制器。无法解释的事实是:如果我提出一个双重问号,它会编译并起作用:

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

有人可以告诉我我错过了什么吗?该怎么办?

1 个答案:

答案 0 :(得分:20)

所需的额外?sourceViewController返回AnyObject而不是UIViewController。这是来自Objective-C的API转换中的一个缺陷(其中这样的属性返回一个相当无意义的id)。从iOS 8 beta 5开始,它仍然是一个持续的过程,显然这些API尚未修复。

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

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

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

AnyObject可以表示任何对象类型,就像id中的Objective-C一样。因此,在编译时,您可以在其上调用任何现有方法,例如sourceViewController

执行此操作时,会触发从AnyObjectUIViewController并根据official guide隐式向下转发:

  

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

所以当你这样做时

self.sourceViewController.presentingViewController??

它隐含地转换为类似

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

这就是为什么你需要两个?:一个用于解决向下转换,一个用于presentingViewController

最后,始终根据文档:

  

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

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