我正在尝试Binding
从变量中使用 SwiftUI 的成员@Binding
(通过它对 的支持@dynamicMemberLookup
),但即使是一个简单的示例,我也可以重新创建多个问题。我最好的猜测是我使用不正确,但网上的文档和示例会提出其他建议。
主要问题(可在 Catalina、Big Sur 和 iPadOS 13 和 14 上重现)是在视图打开时删除项目会触发崩溃并出现索引超出范围错误。
Fatal error: Index out of range: file /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1103.8.25.8/swift/stdlib/public/core/ContiguousArrayBuffer.swift, line 444
第二个问题发生在 Catalina 的文本字段中,尝试编辑文本会隐藏左侧/导航视图。(在 Big Sur 上,编辑文本会隐藏右侧/详细视图,由于导航视图的改进,我认为这是同一问题的不同表现形式。)
struct Child: Identifiable, Hashable {
var id = UUID()
var bar: String = "Text"
func hash(into hasher: inout Hasher) {
self.id.hash(into: &hasher)
}
}
struct ChildView: View {
let child: Child
var body: some View {
Text(child.bar)
}
}
struct ChildEditor: View {
@Binding var child: Child
var body: some View {
TextField("Text", text: self.$child.bar)
}
}
struct ContentView: View {
@State var children: [Child] = []
func binding(for child: Child) -> Binding<Child> {
guard let it = children.firstIndex(of: child) else {
fatalError()
}
return $children[it]
}
var plusButton: Button<Image> {
return Button(action: {
self.children.append(Child())
}) {
Image(systemName: "plus")
}
}
func ParentList<Content: View>(_ content: () -> Content) -> some View {
#if os(macOS)
return List(content: content)
.toolbar {
ToolbarItem {
self.plusButton
}
}
// uncomment for 10.15
// return List {
// self.plusButton
// content()
// }
#elseif os(iOS)
return List(content: content)
.navigationBarItems(trailing: self.plusButton)
#endif
}
var body: some View {
NavigationView {
ParentList {
ForEach(children) { child in
NavigationLink(destination: ChildEditor(child: self.binding(for: child))) {
ChildView(child: child)
}
}
.onDelete { offsets in
self.children.remove(atOffsets: offsets)
}
}
}
}
}
我的基本假设是它Binding
本质上存储了一个指针,因此删除指针将变得无效并触发崩溃,并且编辑文本字段会触发父视图的视图更新,使当前内容无效(这由Big Sur 有时会抱怨在视图更新期间修改了状态变量,即使它仅正确用于 a TextField
) 的 init。但是,更改为使用类类型和@ObservedObject
/ @EnvironmentObject
(或@StateObject
)会将崩溃(在 Catalina 和 iPadOS 13/14 上)延迟到执行任何其他导航操作或无效时(在 Big Sur 上)。如果删除也失败,使用tag
选项 inNavigationLink
关闭视图。
第一个问题是:我做错了什么?如果答案是“一切”,那么应该如何在顶级视图中管理一组数据并为嵌套子视图的成员创建绑定?