当前位置: 首页 > 知识库问答 >
问题:

“致命错误:在展开可选值时意外发现nil”是什么意思?

宋丰
2023-03-14

共有1个答案

阳长恨
2023-03-14

这个答案就是社区维基。如果您觉得可以做得更好,请随时编辑!

在Swift中,可选 是一种选项类型:它可以包含原始类型(“wrapped”)中的任何值,也可以不包含任何值(特殊值nil)。在使用可选值之前,必须先展开该值。

Optional是泛型类型,这意味着Optional Optional 是不同的类型--<>中的类型称为包装类型。在下面,可选的是一个枚举,有两种情况:.some(包装的).none,其中.none等效于nil

var anInt: Int = 42
var anOptionalInt: Int? = 42
var anotherOptionalInt: Int?  // `nil` is the default when no value is provided
var aVerboseOptionalInt: Optional<Int>  // equivalent to `Int?`

anOptionalInt = nil // now this variable contains nil instead of an integer

Xcode将通过突出显示一行代码来显示崩溃。问题发生在这条线上。

这种崩溃可能发生在两种不同的强制解包下:

这是通过运算符在可选的。例如:

let anOptionalString: String?
print(anOptionalString!) // <- CRASH
var optionalDouble: Double!   // this value is implicitly unwrapped wherever it's used
print(optionalDouble) // <- CRASH

虽然在某些情况下,您可以使用强制展开,正如您所知道的那样,一个可选项包含一个值,但没有一个地方可以安全地展开该可选项。

这些变量的设计使您可以将它们的赋值推迟到代码的后面。您有责任在访问它们之前确保它们具有价值。但是,因为它们涉及强制展开,所以它们本质上仍然不安全--因为它们假设您的值是非nil,即使指定nil是有效的。

if anOptionalInt != nil {
    print("Contains a value!")
} else {
    print("Doesn’t contain a value.")
}

例如:

if let number = anOptionalInt {
    print("Contains a value! It is \(number)!")
} else {
    print("Doesn’t contain a number")
}

它所做的是首先检查可选的是否包含一个值。如果是这样,那么“unwrapped”值被赋给一个新变量(number)-然后您可以随意使用该变量,就像它是不可选的一样。如果optional不包含值,那么将调用else子句,正如您所期望的那样。

可选绑定的好处是,你可以同时打开多个选项。您可以用逗号分隔语句。如果所有optionals都被打开,该语句将成功。

var anOptionalInt : Int?
var anOptionalString : String?

if let number = anOptionalInt, let text = anOptionalString {
    print("anOptionalInt contains a value: \(number). And so does anOptionalString, it’s: \(text)")
} else {
    print("One or more of the optionals don’t contain a value")
}
if let number = anOptionalInt, number > 0 {
    print("anOptionalInt contains a value: \(number), and it’s greater than zero!")
}
guard let number = anOptionalInt else {
    return
}

例如:

guard let number = anOptionalInt else {
    return
}

print("anOptionalInt contains a value, and it’s: \(number)!")

Guards还支持if语句支持的相同巧妙技巧,例如同时展开多个optionals和使用WHERE子句。

是否使用if或guard语句完全取决于将来的代码是否要求可选语句包含值。

let number = anOptionalInt ?? 0
let number = anOptionalInt != nil ? anOptionalInt! : 0
var foo : Foo?

如果我们想在foo上调用一个不返回任何内容的方法,我们可以简单地执行以下操作:

foo?.doSomethingInteresting()

如果foo包含一个值,将对其调用此方法。如果不这样做,就不会发生任何不好的事情--代码将继续执行。

(这类似于在Objective-C中向nil发送消息)

foo?.bar = Bar()

(这是因为对于不返回任何内容的方法,可选值将返回void?而不是void)

例如:

if (foo?.bar = Bar()) != nil {
    print("bar was set successfully")
} else {
    print("bar wasn’t set successfully")
}

然而,当试图访问属性或调用返回值的方法时,事情变得更加棘手。因为foo是可选的,所以从它返回的任何内容也都是可选的。为了解决这个问题,您可以使用上述方法之一来解压缩返回的optionals,或者在访问方法或调用返回值的方法之前解压缩foo本身。

let optionalQux = foo?.baz?.qux
let anOptionalString:String?

例如:

var anOptionalString:String? = "bar"

anOptionalString = anOptionalString.map {unwrappedString in
    return "foo".stringByAppendingString(unwrappedString)
}

print(anOptionalString) // Optional("foobar")

但是,如果AnoptionalString没有值,则map将返回nil。例如:

var anOptionalString:String?

anOptionalString = anOptionalString.map {unwrappedString in
    return "foo".stringByAppendingString(unwrappedString)
}

print(anOptionalString) // nil

FlatMap的工作原理与Map类似,只是它允许您从闭包正文中返回另一个可选项。这意味着您可以在需要非可选输入的流程中输入可选输入,但本身也可以输出可选输入。

do {
    let result = try someThrowingFunc() 
} catch {
    print(error)
}
do {
    let result = try someThrowingFunc()    
} catch let error as NSError {
    print(error.debugDescription)
}
if let result = try? someThrowingFunc() {
    // cool
} else {
    // handle the failure, but there's no error information available
}
let result = try! someThrowingFunc()

只有在能够证明其结果在上下文中永远不会失败的情况下,才应该使用try!--这是非常罕见的。

大多数情况下,您将使用完整的Do-Try-Catch系统-以及可选的try?,在处理错误并不重要的极少数情况下。

  • 苹果关于Swift Optionals的文档
  • 何时使用和何时不使用隐式展开的Optionals
  • 了解如何调试iOS应用程序崩溃
 类似资料:
  • 问题内容: 我在Swift 中使用了一个,但是当我尝试更改单元格标签的文本时得到了提示。 有人知道吗? 问题答案: 几乎可以肯定,您的重用标识符不正确。 从方法签名中我们可以看到,返回类型是 Implicitly Unwrapped Optional : 这由以下的感叹号决定: 因此,首先要考虑的是什么是“隐式展开的可选”? Swift编程语言告诉我们: 有时,从程序的结构中可以明显看出,在设置了

  • 我有以下代码: 其名称如下: 但是由于某种原因,我得到了以下错误 致命错误:在展开可选值时意外发现nil 在这一行: 请帮忙调试。 这个问题不同于 “致命错误:在展开可选值时意外发现为零”是什么意思? 这是一个更普遍的问题,与期权的展开有关 此问题特别适用于UIImagePickerController

  • 我在Swift中使用,但当我试图更改单元格标签的文本时,我得到了这个结果。 有人知道这件事吗?

  • 我正在使用来显示来自于一个文件恢复数据库的图像,并且当前得到了错误: 致命错误:在展开可选值时意外发现为零。 不太确定如何执行if检查以防止强制展开,因此如果有人能向我展示另一个语法示例,我将不胜感激。 还尝试将其与nil进行比较(正如文章中所建议的:“致命错误:在展开可选值时意外发现nil”是什么意思?)。

  • 问题内容: 我有下面的这段代码,它在调用keyboardWillShowNotification时运行: 我在第二行看到一条错误消息:。基本上,每当我单击textFields之一时,都会调用该键盘通知,并且其中的代码将运行。我知道我发表了声明,但我想知道为什么我对此一无所获。 我不确定如何收到此错误或如何调试它。是因为我正在模拟器中运行它吗? 这是打印notification.userInfo给出

  • 问题内容: 我正在尝试运行此代码,但我不断收到此错误: 致命错误:解开Optional值时意外发现nil 我不明白这意味着什么或为什么得到它。有什么提示吗? 问题答案: 错误是指以下事实:当可选值设置为nil时,您正在访问可选值的参数(例如,当when 为nil时),这很可能是您的两个之一。 如果该行引发异常,则您为nil。验证是否已成功将其连接到Interface Builder文件中的标签。