3

Swift 下 Cocoa 框架中的NSMetadataItem类包含如下函数:

func valueForAttribute(key: String!) -> AnyObject!

我仍在学习强制展开和可选链接之间的区别(和细节)。在上述函数中,这是否意味着:

  1. key参数必须有一个值,并且

  2. 返回值保证有值?

我主要关心的是返回值后面的感叹号- 一旦我分配了返回值:

var isDownloadedVal = item.valueForAttribute(NSMetadataUbiquitousItemIsDownloadedKey)

检查时是否需要包含一个if let块,或者我是否保证它具有我可以安全检查的值?

4

2 回答 2

19

TLDR:Foo!就当它是Foo

许多 Cocoa 调用包含隐式展开的可选选项,他们对它的需求很可能是该功能甚至存在的原因。以下是我建议的思考方式。

首先,让我们考虑一个不涉及AnyObject. 我认为UIDevice是一个很好的例子。

class func currentDevice() -> UIDevice!

这里发生了什么?嗯,总有一个currentDevice。如果返回nil,则表明系统中存在某种深度错误。所以如果我们在 Swift 中构建这个接口,这很可能会返回UIDevice并完成它。但是我们需要连接到 Objective-C,它返回UIDevice*. 现在这不应该是nil,但它在语法上可能nil。现在在 ObjC 中,我们通常会忽略这个事实并且不在nil这里检查(特别是因为nil-messaging 通常是安全的)。

那么我们如何在 Swift 中表达这种情况呢?好吧,从技术上讲,它是一个Optional<UIDevice>,你最终会得到:

class func currentDevice() -> UIDevice?

并且您每次使用它时都需要显式地打开它(最好使用if let块)。那会很快让你发疯,而且毫无意义。currentDevice()总是返回一个值。这Optional是桥接到 ObjC 的工件。

所以他们发明了一个hack来解决这个问题(我认为这确实是一个hack;如果没有ObjC,我无法想象构建这个功能)。那个hack说,是的,它是一个Optional,但你可以假装它不是,我们保证它总是一个值。

那就是!。对于这种东西,您基本上忽略了!并假装它正在将您退回UIDevice并继续前进。如果他们对你撒谎并返回nil,那么,那将会崩溃。他们不应该对你撒谎。

这暗示了一个规则:除非你真的需要,否则不要使用!(而且你几乎只需要在桥接到 ObjC 时使用)。

在您的具体示例中,这在两个方向上都有效:

func valueForAttribute(key: String!) -> AnyObject!

从技术上讲,它需要一个Optional<String>,但只是因为它桥接到NSString*. 你必须通过非nil这里。从技术上讲,它会返回您Optional<AnyObject>,但这只是因为它已桥接到id. 它保证不会nil

于 2014-06-05T13:21:25.317 回答
1
于 2014-06-05T13:10:35.523 回答