我的Swift程序崩溃与EXC_BAD_INSTRUCTION和以下类似错误之一。这个错误是什么意思,我该如何修复它?
致命错误:在打开可选值时意外地发现nil
or
致命错误:在隐式地展开可选值时意外地发现nil
这篇文章旨在收集“意外发现为零”问题的答案,这样它们就不会分散而难以找到。请随意添加您自己的答案或编辑现有的wiki答案。
我的Swift程序崩溃与EXC_BAD_INSTRUCTION和以下类似错误之一。这个错误是什么意思,我该如何修复它?
致命错误:在打开可选值时意外地发现nil
or
致命错误:在隐式地展开可选值时意外地发现nil
这篇文章旨在收集“意外发现为零”问题的答案,这样它们就不会分散而难以找到。请随意添加您自己的答案或编辑现有的wiki答案。
当前回答
因为上面的答案清楚地解释了如何安全地玩可选项目。 我将试着解释什么是可选的真正在迅速。
声明可选变量的另一种方法是
在 : 可选<Int>
和可选类型只是一个枚举与两种情况,即
enum Optional<Wrapped> : ExpressibleByNilLiteral {
case none
case some(Wrapped)
.
.
.
}
将nil赋值给变量i。我们可以 var i =可选<Int>.无 或者为了赋值,我们会传递一些值 var i =可选<Int>.some(28)
根据swift, 'nil'是没有值。 为了创建一个用nil初始化的实例,我们必须遵守一个叫做expressiblebynillliteral的协议,如果你猜到了,很好,只有optional符合expressiblebynillliteral,不鼓励符合其他类型。
expressiblebynilleral有一个叫做init(nilleral:)的方法,它用nil初始化实例。你通常不会调用这个方法,根据swift文档,不建议直接调用这个初始化式,因为每当你初始化一个可选类型时,编译器都会调用它,用nil文字。
就连我自己也不得不(没有双关语的意思)把我的脑袋绕在可选科目上:D 快快乐乐。
其他回答
首先,您应该知道什么是Optional值。 详细信息请参见《Swift编程语言》。
其次,您应该知道可选值有两个状态。一个是全值,另一个是空值。因此,在实现一个可选值之前,应该检查它是哪个状态。
你可以用if let…或者守卫让…Else等等。
还有一种方法,如果你不想在实现之前检查变量的状态,你也可以使用var buildingName = buildingName ??“buildingName”。
这是一个更重要的注释,这就是为什么隐式打开可选选项在调试nil值时可能具有欺骗性。
考虑下面的代码: 它编译时没有错误/警告:
c1.address.city = c3.address.city
然而在运行时,它给出以下错误:致命错误:在打开可选值时意外地发现nil
你能告诉我哪个对象是nil吗?
你不能!
完整的代码是:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var c1 = NormalContact()
let c3 = BadContact()
c1.address.city = c3.address.city // compiler hides the truth from you and then you sudden get a crash
}
}
struct NormalContact {
var address : Address = Address(city: "defaultCity")
}
struct BadContact {
var address : Address!
}
struct Address {
var city : String
}
长话短说,使用var地址:地址!您隐藏了变量可以为nil的可能性,不让其他读取器看到。当它崩溃的时候,你会想“搞什么鬼?!”我的地址不是可选的,所以我为什么要崩溃?!
因此,最好这样写:
c1.address.city = c2.address!.city // ERROR: Fatal error: Unexpectedly found nil while unwrapping an Optional value
你能告诉我哪个对象是nil吗?
这一次,代码对您来说更清楚了。您可以合理地认为,可能是强行打开了address参数。
完整的代码是:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var c1 = NormalContact()
let c2 = GoodContact()
c1.address.city = c2.address!.city
c1.address.city = c2.address?.city // not compile-able. No deceiving by the compiler
c1.address.city = c2.address.city // not compile-able. No deceiving by the compiler
if let city = c2.address?.city { // safest approach. But that's not what I'm talking about here.
c1.address.city = city
}
}
}
struct NormalContact {
var address : Address = Address(city: "defaultCity")
}
struct GoodContact {
var address : Address?
}
struct Address {
var city : String
}
TL;博士回答
除了极少数例外,这条规则是黄金法则:
避免使用!
声明变量是可选的(?),而不是隐式地打开可选的(IUO) (!)
换句话说,应该使用: var nameOfDaughter:字符串?
而不是: var nameOfDaughter:字符串!
使用if let或guard let展开可选变量
要么像这样展开变量:
if let nameOfDaughter = nameOfDaughter {
print("My daughters name is: \(nameOfDaughter)")
}
或者像这样:
guard let nameOfDaughter = nameOfDaughter else { return }
print("My daughters name is: \(nameOfDaughter)")
这个答案是简洁的,为了充分理解阅读接受的答案
资源
避免强制展开
我在从表视图控制器到视图控制器进行segue时遇到了这个错误,因为我忘记在主故事板中为视图控制器指定自定义类名。
一些简单的东西值得检查,如果其他看起来都没问题
如果我的情况下,我设置一个变量UILabel为nil。
所以我修复了它,之后它就没有抛出错误了。
代码片段
class ResultViewController: UIViewController {
@IBOutlet weak var resultLabel: UILabel!
var bmiValue=""
override func viewDidLoad() {
super.viewDidLoad()
print(bmiValue)
resultLabel.text=bmiValue //where bmiValue was nil , I fixed it and problem was solved
}
@IBAction func recaculateBmi(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
}