为什么Swift的隐式解包可选类型会是`nil`?

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

请原谅我的无知,我可能错过了一些关于可选项的基本理解。我认为 !,即隐式展开的可选项指示符,是一个保证该类型变量不为 nil 的标志。然而,这个非常直接的苹果 API 偶尔会返回给我 nil
这是意外的 bug 还是 Optional 的规范之一?如果这是规范的一部分,我不明白为什么首先要使用可选项,而不是只有可能存在或者为 nil 的变量。

1
nil和空数组不是同一回事。 - Sulthan
这是因为苹果还没有完成将所有库转换为使用Objective-C的nullability注释。 - nhgrif
3个回答

7
我认为,隐式解包可选项标志“!”意味着该类型的变量保证不为空。但很抱歉这是一个误解。隐式解包可选项确实可以是nil。只有没有任何可选限定符(既不是“?”也不是“!”)声明的内容才能保证非nil。因此:
var definitelyCouldBeNilForcedToCheck: String?
var mightBeNilButProbablyNotBECAREFUL: String!
var definitelyNotEverNil: String

有两种情况需要使用隐式解包可选项:

  1. When you are absolutely positively certain that your value won’t be nil, except briefly in very controlled circumstances. For example suppose you have a function that does some processing in its failable initializer. Like this:

    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. When you have a massive corpus of Objective-C (lets say, Cocoa or UIKit), and you have no idea when some pointer is returned whether it can be nil or not. And most of the time you think it probably isn’t, and it would be really annoying to make your API users have to unwrap stuff constantly, but then again, you don’t know for certain it can’t be nil and you want them to read the documentation instead. But they’ll probably forget, but what can you do? Eventually you’ll audit all the functions and then make them optionals or non-nullable values.


1
每当你看到一个带有 ! 运算符的方法签名时,你必须检查它是否为 nil
在大多数情况下,参数将是一个隐式解包可选项,因为它来自一个尚未更新以考虑 Objective-C 可空性注释的 Objective-C 库(Objective-C 源代码文件用于告诉 Swift 参数是否应该是可选项)。
Objective-C 不支持可选项的概念。
如果这来自于 Apple 的库,他们很快会发布 Xcode 更新,解决这个问题并将参数更改为非可选或可选。Apple 没有长期计划在其参数中保留任何隐式解包可选项。

0

不,这个符号!并不能保证变量不是nil。

在Swift中,可选项很棘手。

假设你有以下类型为String的变量:

var name: String?

这不是一个字符串。它是一个可选的字符串,这是一件不同的事情。

然而以下内容:

var name: String!

是一个隐式解包的可选项,这意味着调用名称将始终返回字符串而不是可能为nil的可选字符串。

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


不完全是这样。如果你把那个名字放在字符串里,像这样:let variable = "\(name)",那么这个变量会变成类似于"Optional(some_value)"的东西。!只是表示该值很可能不为nil,所以解包应该是安全的。但是,如果代码使用了nil值,你始终需要检查是否为nil,否则代码可能会崩溃。最好尽量不使用!。对于可选项,请使用?,对于不能为nil的值,请不要使用可选项,这样就不会忘记检查是否为nil。 - Paulius Vindzigelskis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接