在 swift 和领域中展开可选值
Unwrapping an Optional value in swift and realm
我为应用程序编写了一个工作函数,但出现错误“当隐式部署可选值时意外发现 nil 值”限制限制 label.the 文本我无法修复。
属性:
@IBOutlet weak var limitLabel: UILabel!
函数:
func leftLabels(){
let limit = self.realm.objects(Limit.self)
guard limit.isEmpty == false else {return}
limitLabel.text = limit[0].limitSum //Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
let calendar = Calendar.current
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd HH:mm"
let firstDay = limit[0].limitDate as Date
let lastDay = limit[0].limitLastDate as Date
let firstComponent = calendar.dateComponents([.year, .month, .day], from: firstDay)
let lastComponent = calendar.dateComponents([.year, .month, .day], from: lastDay)
let startDate = formatter.date(from: "\(firstComponent.year!)/\(firstComponent.month!)/\(firstComponent.day!) 00:00")
let endDate = formatter.date(from: "\(lastComponent.year!)/\(lastComponent.month!)/\(lastComponent.day!) 23:59")
let filterLimit: Int = realm.objects(SpendingDB.self).filter("self.date >= %@ && self.date <= %@", startDate ?? "", endDate ?? "").sum(ofProperty: "cost")
ForThePeriod.text = "\(filterLimit)"
let a = Int(limitLabel.text!)!
let b = Int(ForThePeriod.text!)!
let c = a - b
availableForSpending.text = "\(c)"
如果你告诉我正确的密码我会很高兴
根据评论,如果您的视图似乎尚未加载,并且您的某些视图仍在 nil
。您的应用程序崩溃是因为在行 limitLabel.text = limit[0].limitSum
中 limitLabel
是 nil
。即使调用 limitLabel.text = "Hello world!"
,它也会崩溃,无论 Realm 是什么
您始终可以保护您需要的数据,以避免更改您的代码。只需添加
guard let limitLabel = limitLabel else { return nil }
guard let ForThePeriod = ForThePeriod else { return nil }
等等。
我试着清理一下你的代码。很难理解你到底想达到什么目的,但像下面这样的东西似乎更合适一点:
func leftLabels() {
// Elements needed for method to execute.
guard let limitLabel = limitLabel else { return }
guard let forThePeriodLabel = forThePeriodLabel else { return }
guard let availableForSpendingLabel = availableForSpendingLabel else { return }
// Items that will be reused throughout the method later on
let limits: [Limit]
let firstLimit: Limit
let dates: (start: Date?, end: Date?)
let filterLimit: Int
limits = self.realm.objects(Limit.self)
guard limits.isEmpty == false else { return }
firstLimit = limits[0]
// limitLabel
limitLabel.text = firstLimit.limitSum
// Date components
dates = {
let calendar = Calendar.current
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd HH:mm"
let firstDay = firstLimit.limitDate as Date
let lastDay = firstLimit.limitLastDate as Date
let firstComponent = calendar.dateComponents([.year, .month, .day], from: firstDay)
let lastComponent = calendar.dateComponents([.year, .month, .day], from: lastDay)
let startDate = formatter.date(from: "\(firstComponent.year!)/\(firstComponent.month!)/\(firstComponent.day!) 00:00")
let endDate = formatter.date(from: "\(lastComponent.year!)/\(lastComponent.month!)/\(lastComponent.day!) 23:59")
return (startDate, endDate)
}()
// forThePeriodLabel
filterLimit = realm.objects(SpendingDB.self).filter("self.date >= %@ && self.date <= %@", startDate ?? "", endDate ?? "").sum(ofProperty: "cost")
forThePeriodLabel.text = String(filterLimit)
// availableForSpendingLabel
availableForSpendingLabel.text = {
guard let a = Int(firstLimit.limitSum) else { return "" }
let b = filterLimit
let c = a - b
return String(c)
}()
}
记下一些有助于您更好地构建和解决代码的做法。
- 危险数据先防
- 为您的方法创建一个可重复使用的项目列表(在大多数情况下应该越少越好 none)。请注意稍后如何将这些分配给。如果你在分配给它之前尝试使用它,你的编译器会警告你。
- 将尽可能多的代码包装到封闭的部分中,例如
availableForSpendingLabel.text = { ... code here ... }()
- 使用元组,例如
let dates: (start: Date?, end: Date?)
- 不要害怕使用长名称,例如
availableForSpendingLabel
我什至会进一步尝试将其分解为多种方法。但是我不确定这个方法是做什么的,假设你只发布了其中的一部分...
========== 编辑:添加替代方法 ==========
根据评论,这是一个财务应用程序,因此可能至少处理 Decimal
个数字是有意义的。还介绍了添加内部解析数据的新结构的方法。格式化程序也用于格式化数字。以及其他一些改进:
struct Limit {
let amount: Decimal
let startDate: Date
let endDate: Date
}
struct Spending {
let cost: Decimal
let date: Date
}
struct LimitReport {
let limitAmount: Decimal
let spendingSum: Decimal
let balance: Decimal
init(limit: Limit) {
let limitAmount: Decimal = limit.amount
let spendingSum: Decimal = {
let calendar = Calendar.autoupdatingCurrent // Is this OK or should it be some UTC or something?
func beginningOfDate(_ date: Date) -> Date {
let components = calendar.dateComponents([.day, .month, .year], from: date)
return calendar.date(from: components)!
}
let startDate = beginningOfDate(limit.startDate)
let endDate = calendar.date(byAdding: .day, value: 1, to: startDate)
let spendings: [Spending] = realm.objects(Spending.self).filter { [=12=].date >= startDate && [=12=].date < endDate }
return spendings.reduce(0, { [=12=] + .cost })
}()
let balance = limitAmount - spendingSum
self.limitAmount = limitAmount
self.spendingSum = spendingSum
self.balance = balance
}
}
func leftLabels() {
// Elements needed for method to execute.
guard let limitLabel = limitLabel else { return }
guard let forThePeriodLabel = forThePeriodLabel else { return }
guard let availableForSpendingLabel = availableForSpendingLabel else { return }
guard let limit = self.realm.objects(Limit.self).first else { return }
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencySymbol = "$"
let report = LimitReport(limit: limit)
limitLabel.text = formatter.string(from: report.limitAmount)
forThePeriodLabel.text = formatter.string(from: report.spendingSum)
availableForSpendingLabel.text = formatter.string(from: report.balance)
}
Matic 为您的问题(已投票)提供了一个很好、全面的答案。我想我会提供一个专门针对您的崩溃的答案以及一个“简短而甜蜜”的修复方法:
有问题的行可能会以两种不同的方式崩溃:
limitLabel.text = limit[0].limitSum //Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
您的 limitLabel
IBOutlet 被声明为“隐式解包可选”(注意类型后的 !
,UILabel
:
@IBOutlet weak var limitLabel: UILabel!
隐式展开的 Optional 是一个 Optional,本质上,编译器添加了一个隐藏的“!”每次尝试引用该对象时强制解包。
也就是说
limitLabel.text = //something
编译为
limitLabel!.text = //something
如果 limitLabel
为零,你就会崩溃。
如果您在加载视图之前调用 leftLabels()
函数,或者如果该插座从未连接,您将会崩溃。
您可以通过向语句添加可选的解包来解决此问题:
limitLabel?.text = //something
(该构造称为“可选链接”。)
鉴于您收到的崩溃消息提到“隐式解包一个可选值”,很可能这就是您的案例中发生崩溃的原因。但是,您还应该解决其他问题。
导致崩溃的第二种方式是数组索引。
limitLabel.text = limit[0].limitSum
当您按索引从数组中获取对象时,如果数组不包含该索引处的项目,您的应用程序将会崩溃。如果 limit
数组为空,表达式 limit[0]
将崩溃。
数组类型有一个计算的 属性 first
,如果数组为空,它将 return 一个可选的。
您应该将其更改为 limit.first?.limitSum
.
将整行更改为:
limitLabel?.text = limit.first()?.limitSum
它不会再崩溃了。
我为应用程序编写了一个工作函数,但出现错误“当隐式部署可选值时意外发现 nil 值”限制限制 label.the 文本我无法修复。
属性:
@IBOutlet weak var limitLabel: UILabel!
函数:
func leftLabels(){
let limit = self.realm.objects(Limit.self)
guard limit.isEmpty == false else {return}
limitLabel.text = limit[0].limitSum //Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
let calendar = Calendar.current
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd HH:mm"
let firstDay = limit[0].limitDate as Date
let lastDay = limit[0].limitLastDate as Date
let firstComponent = calendar.dateComponents([.year, .month, .day], from: firstDay)
let lastComponent = calendar.dateComponents([.year, .month, .day], from: lastDay)
let startDate = formatter.date(from: "\(firstComponent.year!)/\(firstComponent.month!)/\(firstComponent.day!) 00:00")
let endDate = formatter.date(from: "\(lastComponent.year!)/\(lastComponent.month!)/\(lastComponent.day!) 23:59")
let filterLimit: Int = realm.objects(SpendingDB.self).filter("self.date >= %@ && self.date <= %@", startDate ?? "", endDate ?? "").sum(ofProperty: "cost")
ForThePeriod.text = "\(filterLimit)"
let a = Int(limitLabel.text!)!
let b = Int(ForThePeriod.text!)!
let c = a - b
availableForSpending.text = "\(c)"
如果你告诉我正确的密码我会很高兴
根据评论,如果您的视图似乎尚未加载,并且您的某些视图仍在 nil
。您的应用程序崩溃是因为在行 limitLabel.text = limit[0].limitSum
中 limitLabel
是 nil
。即使调用 limitLabel.text = "Hello world!"
您始终可以保护您需要的数据,以避免更改您的代码。只需添加
guard let limitLabel = limitLabel else { return nil }
guard let ForThePeriod = ForThePeriod else { return nil }
等等。
我试着清理一下你的代码。很难理解你到底想达到什么目的,但像下面这样的东西似乎更合适一点:
func leftLabels() {
// Elements needed for method to execute.
guard let limitLabel = limitLabel else { return }
guard let forThePeriodLabel = forThePeriodLabel else { return }
guard let availableForSpendingLabel = availableForSpendingLabel else { return }
// Items that will be reused throughout the method later on
let limits: [Limit]
let firstLimit: Limit
let dates: (start: Date?, end: Date?)
let filterLimit: Int
limits = self.realm.objects(Limit.self)
guard limits.isEmpty == false else { return }
firstLimit = limits[0]
// limitLabel
limitLabel.text = firstLimit.limitSum
// Date components
dates = {
let calendar = Calendar.current
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd HH:mm"
let firstDay = firstLimit.limitDate as Date
let lastDay = firstLimit.limitLastDate as Date
let firstComponent = calendar.dateComponents([.year, .month, .day], from: firstDay)
let lastComponent = calendar.dateComponents([.year, .month, .day], from: lastDay)
let startDate = formatter.date(from: "\(firstComponent.year!)/\(firstComponent.month!)/\(firstComponent.day!) 00:00")
let endDate = formatter.date(from: "\(lastComponent.year!)/\(lastComponent.month!)/\(lastComponent.day!) 23:59")
return (startDate, endDate)
}()
// forThePeriodLabel
filterLimit = realm.objects(SpendingDB.self).filter("self.date >= %@ && self.date <= %@", startDate ?? "", endDate ?? "").sum(ofProperty: "cost")
forThePeriodLabel.text = String(filterLimit)
// availableForSpendingLabel
availableForSpendingLabel.text = {
guard let a = Int(firstLimit.limitSum) else { return "" }
let b = filterLimit
let c = a - b
return String(c)
}()
}
记下一些有助于您更好地构建和解决代码的做法。
- 危险数据先防
- 为您的方法创建一个可重复使用的项目列表(在大多数情况下应该越少越好 none)。请注意稍后如何将这些分配给。如果你在分配给它之前尝试使用它,你的编译器会警告你。
- 将尽可能多的代码包装到封闭的部分中,例如
availableForSpendingLabel.text = { ... code here ... }()
- 使用元组,例如
let dates: (start: Date?, end: Date?)
- 不要害怕使用长名称,例如
availableForSpendingLabel
我什至会进一步尝试将其分解为多种方法。但是我不确定这个方法是做什么的,假设你只发布了其中的一部分...
========== 编辑:添加替代方法 ==========
根据评论,这是一个财务应用程序,因此可能至少处理 Decimal
个数字是有意义的。还介绍了添加内部解析数据的新结构的方法。格式化程序也用于格式化数字。以及其他一些改进:
struct Limit {
let amount: Decimal
let startDate: Date
let endDate: Date
}
struct Spending {
let cost: Decimal
let date: Date
}
struct LimitReport {
let limitAmount: Decimal
let spendingSum: Decimal
let balance: Decimal
init(limit: Limit) {
let limitAmount: Decimal = limit.amount
let spendingSum: Decimal = {
let calendar = Calendar.autoupdatingCurrent // Is this OK or should it be some UTC or something?
func beginningOfDate(_ date: Date) -> Date {
let components = calendar.dateComponents([.day, .month, .year], from: date)
return calendar.date(from: components)!
}
let startDate = beginningOfDate(limit.startDate)
let endDate = calendar.date(byAdding: .day, value: 1, to: startDate)
let spendings: [Spending] = realm.objects(Spending.self).filter { [=12=].date >= startDate && [=12=].date < endDate }
return spendings.reduce(0, { [=12=] + .cost })
}()
let balance = limitAmount - spendingSum
self.limitAmount = limitAmount
self.spendingSum = spendingSum
self.balance = balance
}
}
func leftLabels() {
// Elements needed for method to execute.
guard let limitLabel = limitLabel else { return }
guard let forThePeriodLabel = forThePeriodLabel else { return }
guard let availableForSpendingLabel = availableForSpendingLabel else { return }
guard let limit = self.realm.objects(Limit.self).first else { return }
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencySymbol = "$"
let report = LimitReport(limit: limit)
limitLabel.text = formatter.string(from: report.limitAmount)
forThePeriodLabel.text = formatter.string(from: report.spendingSum)
availableForSpendingLabel.text = formatter.string(from: report.balance)
}
Matic 为您的问题(已投票)提供了一个很好、全面的答案。我想我会提供一个专门针对您的崩溃的答案以及一个“简短而甜蜜”的修复方法:
有问题的行可能会以两种不同的方式崩溃:
limitLabel.text = limit[0].limitSum //Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
您的 limitLabel
IBOutlet 被声明为“隐式解包可选”(注意类型后的 !
,UILabel
:
@IBOutlet weak var limitLabel: UILabel!
隐式展开的 Optional 是一个 Optional,本质上,编译器添加了一个隐藏的“!”每次尝试引用该对象时强制解包。
也就是说
limitLabel.text = //something
编译为
limitLabel!.text = //something
如果 limitLabel
为零,你就会崩溃。
如果您在加载视图之前调用 leftLabels()
函数,或者如果该插座从未连接,您将会崩溃。
您可以通过向语句添加可选的解包来解决此问题:
limitLabel?.text = //something
(该构造称为“可选链接”。)
鉴于您收到的崩溃消息提到“隐式解包一个可选值”,很可能这就是您的案例中发生崩溃的原因。但是,您还应该解决其他问题。
导致崩溃的第二种方式是数组索引。
limitLabel.text = limit[0].limitSum
当您按索引从数组中获取对象时,如果数组不包含该索引处的项目,您的应用程序将会崩溃。如果 limit
数组为空,表达式 limit[0]
将崩溃。
数组类型有一个计算的 属性 first
,如果数组为空,它将 return 一个可选的。
您应该将其更改为 limit.first?.limitSum
.
将整行更改为:
limitLabel?.text = limit.first()?.limitSum
它不会再崩溃了。