【问题标题】:How to create an instance of an object in SwiftUI without duplication?如何在不重复的情况下在 SwiftUI 中创建对象的实例?
【发布时间】:2019-11-13 20:17:30
【问题描述】:

这是that问题的下一部分。

我有以下代码。

应用的初始视图:

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 是 @BindableObjects,因为它们的更改由 SwiftUI 本身管理。

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

  • 首先 MyObjectObjectsListView 初始化时创建。
  • 第二个MyObject 在其PresentationButton 按下时创建(预期的)。
  • 第三个(有时甚至第四个)MyObject 在关闭 ObjectsDetailView 时创建。

所以我不知道我应该使用什么模式来只创建一个对象?

我唯一要做的就是制作以下代码:

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

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

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

【问题讨论】:

  • 我刚刚用虚拟对象测试了这个,我看到了一个初始化,它是在计算视图主体的时候。当PresentationButton 被点击或视图被关闭时,我没有看到另一个初始化。您确定该对象已多次初始化吗?你怎么知道(在对象的init 中打印语句?)?额外的对象是与您要创建的对象重复还是不同?
  • @RPatel99 感谢您,我找到了解决方案。感谢您的支持!我会用示例项目更新问题,其中第一次提交代表重复错误,第二次显示修复。

标签: ios swift swiftui


【解决方案1】:

我已经找到了解决办法。

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

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

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

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

注意:rep 中的代码仍然会在每个工作流程演练中创建一个额外的对象。所以它完全创建了两个对象而不是一个。可以通过this answer 中提供的方式修复此行为。

【讨论】:

    猜你喜欢
    • 2018-01-21
    • 1970-01-01
    • 2015-11-14
    • 1970-01-01
    • 2020-07-15
    • 1970-01-01
    • 2021-12-20
    • 2017-02-26
    • 1970-01-01
    相关资源
    最近更新 更多