检查后在 SwiftUI 中将可选绑定设置为 nil 时出现异常
Posted
技术标签:
【中文标题】检查后在 SwiftUI 中将可选绑定设置为 nil 时出现异常【英文标题】:Exception when setting an optional binding to nil in SwiftUI after checking 【发布时间】:2020-09-18 14:53:52 【问题描述】:我有一个带有State
变量的视图,它是一个Optional
。我通过首先检查可选变量是否为 nil 来渲染视图,如果不是,则强制展开它并使用 Binding
将其传递到子视图中。
但是,如果我在值和 nil
之间切换可选变量,应用程序会崩溃,并且我会在函数 BindingOperations.ForceUnwrapping.get(base:)
中得到 EXC_BAD_INSTRUCTION
。如何仅显示“Nil”Text
视图来获得视图的预期功能?
struct ContentView: View
@State var optional: Int?
var body: some View
VStack
if optional == nil
Text("Nil")
else
TestView(optional: Binding($optional)!)
Button(action:
if optional == nil
optional = 0
else
optional = nil
)
Text("Toggle")
struct TestView: View
@Binding var optional: Int
var body: some View
VStack
Text(optional.description)
Button(action:
optional += 1
)
Text("Increment")
【问题讨论】:
【参考方案1】:这是解决此问题的一种可能方法。使用 Xcode 12 / ios 14 测试。
The-Variant! - 永远不要使用可选的状态/绑定和强制解包 :)
Variant1:使用绑定包装器(无其他更改)
CRTestView(optional: Binding(
get: self.optional ?? -1 , set: self.optional = $0
))
Variant2:按原样传输绑定
struct ContentView: View
@State var optional: Int?
var body: some View
VStack
if optional == nil
Text("Nil")
else
CRTestView(optional: $optional)
Button(action:
if optional == nil
optional = 0
else
optional = nil
)
Text("Toggle")
struct CRTestView: View
@Binding var optional: Int?
var body: some View
VStack
Text(optional?.description ?? "-1")
Button(action:
optional? += 1
)
Text("Increment")
【讨论】:
这在此示例中确实有效,但是,在较大的应用程序中,这意味着必须始终检查不理想的可选选项。进行 nil 检查的目的是避免在子视图中出现可选项。 谢谢,这很有帮助,但我不会将其标记为答案,因为在您完成 nil 检查后提供默认值似乎是多余的。【参考方案2】:我刚刚找到了一个不涉及手动创建绑定和/或硬编码默认值的解决方案,因此您可以执行以下操作:
if let unwrappedBinding = $optional.unwrappedValue
TestView(optional: unwrappedBinding)
else
Text("Nil")
这里是扩展:
protocol OptionalType: ExpressibleByNilLiteral
associatedtype Wrapped
var optional: Wrapped? get set
extension Optional: OptionalType
var optional: Wrapped?
get return self
mutating set self = newValue
extension Binding where Value: OptionalType
/// Converts a Binding with an optional values (`Binding<T?>`) to an optional `Binding<T>?` with an unwrapped value.
var unwrappedValue: Binding<Value.Wrapped>?
guard let unwrappedValue = wrappedValue.optional else
return nil
return .init(get: unwrappedValue , set: wrappedValue.optional = $0 )
这个更容易指定默认值的扩展 ($optional.defaulting(to: 0)
) 也很方便:
/// Converts a Binding with an optional values (`Binding<T?>`) to a non-optional (`Binding<T>`) with a default value.
func defaulting(to defaultValue: Value.Wrapped) -> Binding<Value.Wrapped>
.init(get: self.wrappedValue.optional ?? defaultValue , set: self.wrappedValue.optional = $0 )
【讨论】:
以上是关于检查后在 SwiftUI 中将可选绑定设置为 nil 时出现异常的主要内容,如果未能解决你的问题,请参考以下文章