如何在SwiftUI中正确使用动态成员绑定?
我试图使用SwiftUI的如何在SwiftUI中正确使用动态成员绑定?,swiftui,swiftui-state,Swiftui,Swiftui State,我试图使用SwiftUI的绑定成员来自@Binding变量(通过其对@dynamicMemberLookup的支持),但即使使用一个简单的示例,我也可以重新创建多个问题。我最好的猜测是我没有正确地使用它,但网上的文档和示例会给出相反的建议 主要问题(可在Catalina、Big Sur和iPadOS 13和14上重现)是在视图打开时删除项会触发崩溃,并导致索引超出范围错误 Fatal error: Index out of range: file /AppleInternal/BuildRoot
绑定
成员来自@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子级:可识别、可散列{
var id=UUID()
变量栏:String=“Text”
func散列(放入散列程序:inout散列程序){
self.id.hash(放入:&hasher)
}
}
结构子视图:视图{
让孩子:孩子
var body:一些观点{
文本(child.bar)
}
}
结构子编辑器:视图{
@绑定变量child:child
var body:一些观点{
文本字段(“文本”,文本:self.$child.bar)
}
}
结构ContentView:View{
@状态变量子项:[Child]=[]
func绑定(用于子对象:子对象)->绑定{
guard let it=children.firstIndex(of:child)else{
法塔莱罗()
}
返回$children[it]
}
var plusButton:按钮{
返回按钮(操作:{
self.children.append(Child())
}) {
图像(系统名称:“plus”)
}
}
func父列表(u内容:()->内容)->一些视图{
#如果操作系统(macOS)
退货清单(内容:content)
.工具栏{
工具栏项{
自选按钮
}
}
//10.15的取消注释
//返回列表{
//自选按钮
//内容()
// }
#elseif操作系统(iOS)
退货清单(内容:content)
.navigationBarItems(尾部:self.plusButton)
#恩迪夫
}
var body:一些观点{
导航视图{
父母名单{
ForEach(儿童){child in
NavigationLink(目标:ChildEditor(子:self.binding(for:child))){
子视图(子:子)
}
}
.onDelete{中的偏移量
self.children.remove(原子偏移:偏移)
}
}
}
}
}
我的基本假设是,Binding
本质上存储一个指针,因此删除指针将变得无效并触发崩溃,编辑文本字段将触发父视图的视图更新,从而使当前内容无效(Big Sur有时会抱怨状态变量在视图更新过程中被修改,即使它只正确地用于文本字段的init
)。但是,更改为使用类类型和@ObservedObject
/@EnvironmentObject
(或@StateObject
)会延迟崩溃(在Catalina和iPadOS 13/14上)到何时采取任何其他导航操作或没有任何影响(在Big Sur上)。如果删除操作失败,则使用导航链接中的标记选项关闭视图
第一个问题是:我做错了什么?如果答案是“一切”,如何管理顶级视图中的数据数组并为嵌套子视图创建成员绑定?使用-所有这些情况都已经描述过了我看了一下,有几个解决方案确实与我尝试的方法相匹配,但我仍然会遇到崩溃。我看不出有什么不同。使用-所有这些情况都已经取消scribedI确实看了一眼,有几个解决方案确实符合我正在尝试的,但我仍然遇到了崩溃。我看不出有什么不同。
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)
}
}
}
}
}