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

Posted

技术标签:

【中文标题】双问号,它是如何工作的?【英文标题】:Double question mark, How does it work? 【发布时间】:2014-09-22 18:15:09 【问题描述】:

我正在学习 Swift,作为这个过程的一部分,我试图弄清楚这里到底发生了什么。我有一个自定义 segue,我想在其中放置我的模态视图控制器解除转换。过去在 Objective-c 中是这样的:

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

selfUIStoryboardSegue 的一个实例。 我在 Swift 中将这个 sn-p 翻译为:

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

从编译器得到这个错误:

'UIViewController?'没有名为的成员 'dismissViewControllerAnimated'

现在,by documentation,presentingViewController 方法如下所示:

var presentingViewController: UIViewController?  get 

根据我对 Swift 语言文档的理解,? 应该打开该值(如果有)。在这种情况下,视图控制器。无法解释的事实是:如果我放一个双问号,它会编译并且可以工作:

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

谁能告诉我我错过了什么?那该怎么办?

【问题讨论】:

等待 -1 的原因。我知道这可能是一个 n00b 问题(正如我所说:我正在学习),但我认为我将其表述得很清楚,这不是一个具体案例,也不是我能找到的任何记录。 sourceViewController的声明是什么? @GabrielePetronella 我更新了这个问题。它是 UIStoryboardSegue 的属性。 【参考方案1】:

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

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

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

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

AnyObject 可以表示任何对象类型,就像idObjective-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 运算符强制调用。

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

【讨论】:

解释很清楚,但我想知道一件事:第二个?然后在做什么?第一个返回一个 AnyObject 未包装的实例,但第二个呢?不是必须允许使用该运算符的可选类型吗? @NicolaMiotto 我想我有一个合理的解释,看我上次的更新 非常好@Gabriele,我认为您可以节省一些时间来转换此代码,“让源:UIViewController?= self.sourceViewController as?UIViewController 让呈现:UIViewController?=源?.presentingViewController”这个,“如果让presenting = self.sourceViewController as?UIViewController ”。方便检查选项。 @GeorgeTaskos 是的,这可以做到,尽管 sn-p 仅作为解释,所以我希望尽可能明确。

以上是关于双问号,它是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

?? JavaScript 双问号(空值合并运算符)

TypeScript 中的问号+冒号双问号问号+点感叹号+点

TypeScript 中的问号+冒号双问号问号+点感叹号+点

TypeScript 中的问号+冒号双问号问号+点感叹号+点

解析类型后加问号和双问号

C#中的双问号有啥作用? [复制]