如何在不重复的情况下在 SwiftUI 中创建对象的实例?

How to create an instance of an object in SwiftUI without duplication?

这是 问题的下一部分。

我有以下代码。

应用程序的初始视图:

struct InitialView : View {
    var body: some View {
        Group { 
            PresentationButton(destination: ObjectsListView()) {
                Text("Show ListView")
            }
            PresentationButton(destination: AnotherObjectsListView()) {
                Text("Show AnotherListView")
            }
        }
    }
}

对象的列表视图:

struct ObjectsListView : View {

    @Environment(\.myObjectsStore.objects) var myObjectsStores: Places

    var body: some View {
        Group {    
            Section {
                ForEach(myObjectsStore.objects) { object in
                    NavigationLink(destination: ObjectDetailView(object: object)) {
                        ObjectCell(object: object)
                    }
                }
            }
            Section {
                // this little boi
                PresentationButton(destination: ObjectDetailView(objectToEdit: MyObject(store: myObjectsStore))) {
                    Text("Add New Object")
                }
            }
        }
    }
}

详情查看:

struct ObjectsDetailView : View {

    @Binding var myObject: MyObject    

    var body: some View {
        Text("\(myObject.title)")
    }
}

所以问题比较复杂

  1. ObjectsListView 在计算 body 时在自身初始化时创建 MyObject(store: myObjectsStore) 的实例。
  2. MyObject 对象正在将其 store 属性 设置为自身初始化,因为它应该知道它属于 myObjectsStore 还是 anotherMyObjectsStore
  3. myObjectsStore 是 @BindableObject,因为它们的更改由 SwiftUI 本身管理。

所以这种行为最终导致我进行了意外的 MyObject() 初始化,因为视图正在计算自身。喜欢:

所以我想不出在这种情况下我应该使用什么模式来只创建一个对象?

我唯一要做的就是编写以下代码:

struct ObjectsListView : View {

    @Environment(\.myObjectsStore.objects) var myObjectsStores: Places

    @State var buttonPressed = false

    var body: some View {
        Group {    
            if buttonPressed {
                ObjectDetailView(objectToEdit: MyObject(store: myObjectsStore))
            } else {

                Section {
                    ForEach(myObjectsStore.objects) { object in
                        NavigationLink(destination: ObjectDetailView(object: object)) {
                            ObjectCell(object: object)
                        }
                    }
                }
                Section {
                    Button(action: {
                        self.buttonPressed.toggle()
                    }) {
                        Text("Add New Object")
                    }
                }
            }
        }
    }
}

这只是有条件地重绘 ObjectsListView 到详细视图。但这完全不符合 iOS 准则。那么如何在 SwiftUI 中为另一个视图创建 Only One 对象呢?

更新: 这是代表对象重复错误的 project。 我仍然不知道为什么在这种情况下对象会重复。但至少我知道原因了。原因是这一行:

@Environment(\.myObjectsStore.objects) var myObjectsStores: Places

我尝试与此包装器共享我的模型,以使其在每个视图(包括模态视图)中可用,而无需将它们作为参数传递给新视图初始化程序,其他方式不可用,例如@EnvironmentObject 包装器。出于某种原因 @Environment(\.keyPath) 包装器会产生重复。

所以我只需将所有变量从 Environment(\.) 替换为 ObjectBinding,现在一切正常。

我找到了解决方法。

Here's 表示对象重复错误的项目回购以及修复此问题的版本。我仍然不知道在那种情况下对象是如何复制的。但我想通了为什么。发生这种情况是因为这一行:

@Environment(\.myObjectsStore.objects) var myObjectsStores: MyObjectsStore

我已经使用 @Environment(\.key) 将我的模型连接到导航堆栈中的每个视图,包括 Modal 一个,SwiftUI 中提供的其他方式不可用,例如:@State, @ObjectBinding, @EnvironmentObject。并且出于某种原因 @Environment(\.key) 包装器产生了这些重复项。

所以我只需将所有变量从 @Environment(\.) 替换为 @ObjectBinding,现在几乎一切正常。

注意:代表中的代码仍然通过每个工作流程演练创建一个额外的对象。所以它完全创建了两个对象而不是一个。此行为可以通过 this answer.

中提供的方式修复