我正在学习Swift,并且作为整个过程的一部分,试图找出这里到底发生了什么。我有一个自定义segue,我想放置我的模态视图控制器解除转换。过去在Objective-c中的内容如下:
UIViewController *sourceViewController = self.sourceViewController;
[sourceViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];
self
是UIStoryboardSegue
的一个实例。
我在Swift中将此片段翻译为:
self.sourceViewController.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
从编译器中获取此错误:
“的UIViewController?没有名为的成员 'dismissViewControllerAnimated'
现在,by documentation,presentingViewController
方法如下所示:
var presentingViewController: UIViewController? { get }
根据我对Swift语言文档的理解,?
应解包该值,如果有的话。在这种情况下,视图控制器。无法解释的事实是:如果我提出一个双重问号,它会编译并起作用:
self.sourceViewController.presentingViewController??.dismissViewControllerAnimated(true, completion: nil)
有人可以告诉我我错过了什么吗?该怎么办?
答案 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
。
执行此操作时,会触发从AnyObject
到UIViewController
并根据official guide隐式向下转发:
与Swift中的所有向下转发一样,从
AnyObject
到更具体的对象类型的转换不能保证成功,因此返回一个可选值
所以当你这样做时
self.sourceViewController.presentingViewController??
它隐含地转换为类似
的内容 let source: UIViewController? = self.sourceViewController as? UIViewController
let presenting: UIViewController? = source?.presentingViewController
这就是为什么你需要两个?
:一个用于解决向下转换,一个用于presentingViewController
。
最后,始终根据文档:
当然,如果您确定对象的类型(并且知道它不是nil),则可以使用as运算符强制调用。
这正是我上面提出的解决方案。