Swift 在可空性可用之前使用隐式解包可选

Swift's use of Implicitly Unwrapped Optional before availability of nullability

在 Apple 关于可空性的博客中,他们提到了这一点:

"...in Swift there’s a strong distinction between optional and non-optional references, e.g. NSView vs. NSView?, while Objective-C represents boths of these two types as NSView *. Because the Swift compiler can’t be sure whether a particular NSView * is optional or not, the type is brought into Swift as an implicitly unwrapped optional, NSView!"

这是否意味着之前在 Swift 中将 Objective-C 方法声明为 returning 隐式解包可选时,它实际上可能会崩溃(因为某些方法声明为隐式解包可选可以 return 零)?或者 Apple 是否确保只有那些绝对不会 return nil 的 Objective-C 方法被声明为隐式解包可选?

Apple 的框架没有什么特别之处。一开始,你在 Swift 中使用的 everything (每个对象)是一个隐式展开的可选。那是因为 Objective-C 中的每个指针都可能 return nil.

事实上,即使在 Objective-C 可空性注释的时代,注释为 nonnull 的方法也并非完全不可能 return nil。 Objective-C 不强制执行可空性规则,它只是提供了一种注释代码的方法,因此 应该 从 Swift 开始使用起来更安全。对于 Apple 的框架,我敢打赌您不会遇到这个问题。或者,如果您这样做,Xcode 的下一个版本将修复它。

但是,来自 Objective-C 库和框架的隐式解包选项并没有什么特别之处。隐式解包的可选选项告诉你的唯一一件事是框架作者还没有努力注释他们的库(你不能将隐式解包的选项留在带注释的库中)。 是的,这些隐式展开的选项可以是 nil,它们可能会使您的应用程序崩溃。

就 Apple 而言,如果出于某种原因,你在不同的项目上使用了 Xcode 7 和 Xcode 6,如果你采用了 Xcode 7 的更新注释已声明为非可选,然后假设 Xcode 6 中隐式解包的可选版本永远不会 nil 可能会成功。但是如果你在 Xcode 7 中选择了一些可选的东西,假设来自 Xcode 6 的隐式解包版本永远不会是 nil 可能会使你的应用程序崩溃。

最终,在 Swift 中,我们对隐式解包选项的使用应该很少见。隐式解包选项的主要用途应该主要保留给 class 属性,这些属性不能在 class 初始化 returned 之前设置(例如, @IBOutlets 在视图控制器中).否则,它们很容易成为 Stack Overflow 上众多 "Unexpectedly found nil" 问题的来源。


针对"Why return an implicitly unwrapped optional rather than an optional?"的问题,几点...

首先,这是一道语言设计题。我不在 Objective-C 或 Swift 语言设计团队,这些团队的任何人都不太可能过来回答这个问题...

其次,这就是语言被设计为互操作的方式。任何未添加可空性注释的 Objective-C 文件都将被视为 Swift.

中的所有内容都是隐式解包的可选内容

第三,隐式可选的原因是它减少了可选需要的 if let 等语句的大量冗长,同时不保证变量实际上是 non-nil。造成这种情况的大部分原因可能是因为您认为这些方法中的大多数实际上从来没有 return nil.

第四,如果你知道哪些有机会成为 nil 而哪些没有,你实际上可以继续编写你的 Swift 代码来处理这两个问题关于注释 Objective-C 代码的方式的假设。

例如,对于隐式展开的可选,当然,您可以将其视为非可选,并删除一些与展开相关的次要冗长内容。

此外,如果您认为它可能是 nil,对于隐式展开的可选内容,所有可选的展开内容仍然可以使用它。

示例:

override func someFunc(implicitVal: String!) -> String {
    return implicitVal ?? "It was nil!"
}

override func someOtherFunc(implicitVal: String!) -> String {
    return implicitVal
}

如果我们假设它们都是可选的,第二个例子就不会工作

如果我们假设它们是非可选的,第一个例子就不会起作用。

隐式展开的可选值允许 Swift 开发人员自由地将它们视为任一种,前提是他们对值的可能性做出了正确的假设 nil.

Does that mean previously when declaring Objective-C methods as returning implicitly unwrapped optional in Swift, it can in fact crash (since some of the methods declared with implicitly unwrapped optional may return nil)?

没有。隐式展开的可选值是可选的——这意味着 nil 是一个完全可以接受的值。有一个隐式解包的可选作为 nil 不会崩溃,只有当你尝试直接访问它的成员而没有可选绑定或可选链接时它才会崩溃。

Or does Apple make sure only those Objective-C methods that absolutely do not return nil get declared as implicitly unwrapped optional?

如果已知它不是 return nil,那么 Apple 在审核后会将其声明为非可选的,不是 隐式-展开可选。仅当不知道它是否可以 return nil 时,它是否 return 隐式解包可选。