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

Posted

技术标签:

【中文标题】为啥 Swift 隐式展开可选的“nil”?【英文标题】:Why is a Swift implicitly unwrapped optional `nil`?为什么 Swift 隐式展开可选的“nil”? 【发布时间】:2015-05-20 23:19:33 【问题描述】:
self.presentTextInputControllerWithSuggestions(nil, allowedInputMode: WKTextInputMode.Plain)  (results:[AnyObject]!) -> Void in
    // results can be nil
    if let speech = results.first as? String 
        debugPrint(speech)
    

请原谅我的无知,恐怕我错过了对可选选项的一些基本了解。我的印象是!,隐式展开的可选指示符,保证该类型的变量不为零。然而,这个非常简单的 Apple API 很少会返回给我nil

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

【问题讨论】:

nil 和空数组不一样 这是因为 Apple 尚未完成所有库的转换以使用 Objective-C 可空性注释。 【参考方案1】:

我的印象是!,隐式展开的可选指示符,保证该类型的变量不为零。

恐怕这是一个错误的印象。隐式展开的选项可以是nil。只有没有用任何可选限定符声明的东西,?!,才能保证不是nil

所以:

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

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

    当你绝对肯定你的价值不会是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
        
    
    

    当你有一个庞大的 Objective-C 语料库(比如说,Cocoa 或 UIKit),你不知道什么时候返回某个指针,它是否可以是 nil。大多数时候你认为它可能不是,让你的 API 用户不得不不断地打开东西真的很烦人,但话说回来,你不知道它可以确定 '不为零,您希望他们改为阅读文档。但他们可能会忘记,但你能做什么?最终,您将审核所有函数,然后将它们设为可选项或不可为空的值。

【讨论】:

【参考方案2】:

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

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

Objective-C 不支持可选项的概念。

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

【讨论】:

【参考方案3】:

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

swift 中的选项很棘手。

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

var name: String?

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

但是如下:

var name: String!

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

如果您希望代码在可选项为 nil 时崩溃,通常使用隐式展开的可选项。

【讨论】:

不完全是。如果将该名称放在字符串中,例如 let variable = "\(name)",则该变量将类似于 "Optional(some_value)"。 !仅表示 value 很可能不是 nil ,因此打开它应该是安全的。但是,如果代码使用 nil 值会崩溃,您总是需要检查 nil。最好尽量不要用!一点也不。采用 ?对于不能为 nil 的值的选项和无选项,所以你不会忘记检查 nil

以上是关于为啥 Swift 隐式展开可选的“nil”?的主要内容,如果未能解决你的问题,请参考以下文章

在隐式展开可选值 AVAUDIO Player SWIFT 时意外发现 nil

Swift Xcode 致命错误:在隐式展开可选值时意外发现 nil [重复]

发现可选值错误 nil swift 3

致命错误:在展开可选值时意外发现 nil - 为啥?

Nil 同时展开可选的 IBOutlet 值

在隐式展开可选值时意外发现 nil (UICollectionView)