我的Swift程序崩溃与EXC_BAD_INSTRUCTION和以下类似错误之一。这个错误是什么意思,我该如何修复它?
致命错误:在打开可选值时意外地发现nil
or
致命错误:在隐式地展开可选值时意外地发现nil
这篇文章旨在收集“意外发现为零”问题的答案,这样它们就不会分散而难以找到。请随意添加您自己的答案或编辑现有的wiki答案。
我的Swift程序崩溃与EXC_BAD_INSTRUCTION和以下类似错误之一。这个错误是什么意思,我该如何修复它?
致命错误:在打开可选值时意外地发现nil
or
致命错误:在隐式地展开可选值时意外地发现nil
这篇文章旨在收集“意外发现为零”问题的答案,这样它们就不会分散而难以找到。请随意添加您自己的答案或编辑现有的wiki答案。
当前回答
这个问题在《SO》杂志上经常出现。这是Swift新开发人员首先要解决的问题之一。
背景:
Swift使用“可选项”的概念来处理可能包含值或不包含值的值。在C等其他语言中,可以在变量中存储0值,以表示它不包含任何值。但是,如果0是一个有效值呢?然后你可以用-1。如果-1是一个有效值怎么办?等等。
Swift可选选项允许您设置任何类型的变量,以包含有效值或无值。
当将变量声明为mean(类型x,或无值)时,在类型后加上一个问号。
可选对象实际上是一个容器,它要么包含给定类型的变量,要么什么都不包含。
为了获取其中的值,一个可选对象需要“解包装”。
“!”操作符是一个“强制展开”操作符。上面写着“相信我。我知道我在做什么。我保证当这段代码运行时,变量将不包含nil。”如果你错了,你就会崩溃。
除非您确实知道自己在做什么,否则请避免使用“!”强制展开操作符。对于初学者来说,它可能是最大的崩溃来源。
如何处理可选选项:
还有很多其他更安全的方法来处理可选选项。以下是一些(不是详尽的列表)
您可以使用“可选绑定”或“if let”来表示“如果这个可选包含一个值,则将该值保存到一个新的非可选变量中。”如果optional不包含值,则跳过该If语句的语句体”。
下面是一个使用foo optional进行可选绑定的例子:
if let newFoo = foo //If let is called optional binding. {
print("foo is not nil")
} else {
print("foo is nil")
}
注意,使用可选投标时定义的变量只存在于if语句体中(仅“在作用域内”)。
或者,你可以使用一个guard语句,它允许你在变量为nil时退出你的函数:
func aFunc(foo: Int?) {
guard let newFoo = input else { return }
//For the rest of the function newFoo is a non-optional var
}
在Swift 2中增加了警卫声明。Guard允许您在代码中保留“黄金路径”,并避免由于使用“if let”可选绑定而导致的不断增加的嵌套if级别。
还有一种构造叫做“nil合并运算符”。它的形式是“optional_var ??”replacement_val”。它返回一个与可选变量中包含的数据类型相同的非可选变量。如果可选对象包含nil,它将返回"??"符号后面的表达式值。
所以你可以使用这样的代码:
let newFoo = foo ?? "nil" // "??" is the nil coalescing operator
print("foo = \(newFoo)")
您也可以使用try/catch或guard错误处理,但通常上述另一种技术更简洁。
编辑:
另一个更微妙的问题是“隐式地展开可选项”。当我们声明foo时,我们可以说:
var foo: String!
在这种情况下,foo仍然是可选的,但你不必打开它来引用它。这意味着任何时候你试图引用foo,如果它是nil,就会崩溃。
这段代码:
var foo: String!
let upperFoo = foo.capitalizedString
将在引用foo的capitalizedString属性时崩溃,即使我们没有强制展开foo。指纹看起来很好,但实际上不是。
因此,您要非常小心地使用隐式展开的可选项。(甚至可能完全避免它们,直到你对可选选项有了充分的理解。)
底线:当你第一次学习Swift时,假装“!”字符不是语言的一部分。这很可能会给你带来麻烦。
其他回答
首先,您应该知道什么是Optional值。 详细信息请参见《Swift编程语言》。
其次,您应该知道可选值有两个状态。一个是全值,另一个是空值。因此,在实现一个可选值之前,应该检查它是哪个状态。
你可以用if let…或者守卫让…Else等等。
还有一种方法,如果你不想在实现之前检查变量的状态,你也可以使用var buildingName = buildingName ??“buildingName”。
因为上面的答案清楚地解释了如何安全地玩可选项目。 我将试着解释什么是可选的真正在迅速。
声明可选变量的另一种方法是
在 : 可选<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 快快乐乐。
如果我的情况下,我设置一个变量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)
}
}
Xcode 12 iOS 14 Swift 5
我的问题是导航类型,因为我直接调用vie控制器,而没有实例化故事板,这意味着数据还没有从故事板设置。
当你导航时,用
let homeViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "home") as? HomeEventsViewController
homeViewController?.modalTransitionStyle = .crossDissolve
homeViewController?.modalPresentationStyle = .fullScreen
view.present(homeViewController ?? UIViewController(), animated: true, completion: nil)
希望它能起作用:-)
如果在CollectionView中出现此错误,请尝试创建CustomCell文件和Custom xib。
在mainVC的ViewDidLoad()中添加此代码。
let nib = UINib(nibName: "CustomnibName", bundle: nil)
self.collectionView.register(nib, forCellWithReuseIdentifier: "cell")