为什么 Swift 隐式展开可选的“nil”?

Why is a Swift implicitly unwrapped optional `nil`?

self.presentTextInputControllerWithSuggestions(nil, allowedInputMode: WKTextInputMode.Plain) { (results:[AnyObject]!) -> Void in
    // results can be nil
    if let speech = results.first as? String {
        debugPrint(speech)
    }
}

请原谅我的无知,恐怕我错过了对可选值的一些基本理解。我的印象是 !,隐式解包的可选指示符,保证该类型的变量不为零。然而,这个非常直截了当的苹果 API 很少 return 我 nil.

这是意外错误还是可选规范的一部分?因为如果这是规范的一部分,我不明白为什么首先有选项而不是可以存在或 nil 的变量。

不,这个符号!不能保证变量不为零。

swift 中的选项很棘手。

假设您有以下字符串类型的变量

var name: String?

这不是字符串。这是一个可选的字符串,这是另一回事。

然而如下:

var name: String!

是一个隐式展开的可选字符串,这意味着调用 name 将始终给出字符串而不是可选字符串,后者可能为 nil。

如果您希望代码在可选为 nil 时崩溃,通常使用隐式解包可选。

每当您看到像这样带有 ! 运算符的方法签名时,您 必须 检查它是否 nil

在大多数情况下,该参数将是一个隐式展开的可选参数,因为它来自 Objective-C 库,该库尚未更新以说明 Objective-C 可空性注释(Objective-C 源代码文件用于告诉 Swift 参数是否应该是可选的)。

Objective-C 不支持可选的想法。

如果这是来自 Apple 库,他们发布 Xcode 更新只是时间问题,该更新将解决此问题并将参数更改为非可选或可选。 Apple 没有在其参数中保留任何隐式展开的可选值的长期计划。

I'm under the impression that !, the implictly unwrapped optional indicator, is a guarantee that the variable of that type is not nil.

恐怕这是一种错误的印象。隐式展开的可选值可以是 nil。只有没有用任何可选限定符声明的东西,既不是 ? 也不是 !,保证是非 nil.

所以:

var definitelyCouldBeNilForcedToCheck: String?
var mightBeNilButProbablyNotBECAREFUL: String!
var definitelyNotEverNil: String

隐式解包选项有两个用例:

  1. 当您绝对肯定您的价值不会 nil 时,除非在非常受控的情况下短暂。例如,假设您有一个函数在其可失败初始化器中进行一些处理。像这样:

    class FileHandler {
        let fileHandle: SomeFileHandleType!
    
        init?(fileName: String) {
            fileHandle = open(fileName)
            if fileHandle == nil { return nil }
        }
    
        deinit {
            if fileHandle != nil {
                fileHandle.close()
            }
        }
    
        func variousMethods() {
            // can just use fileHandle without bothering about
            // unwrapping it, because it cannot possibly be nil
            // based on how you’ve written your code
        }
    }
    
  2. 当你有一个庞大的 Objective-C 语料库(比方说 Cocoa 或 UIKit)时,你不知道什么时候返回某个指针是否可以 nil 还是不行。大多数时候你认为它可能不是,让你的 API 用户不得不不断打开东西真的很烦人,但话又说回来,你不知道 某些 不能为 nil 并且您希望他们改为阅读文档。但他们可能会忘记,但你能做什么?最终您将审核所有函数,然后将它们设为可选值或不可空值。