This is the next part of that question.
I've got the follow code.
The initial view of the app:
struct InitialView : View {
var body: some View {
Group {
PresentationButton(destination: ObjectsListView()) {
Text("Show ListView")
}
PresentationButton(destination: AnotherObjectsListView()) {
Text("Show AnotherListView")
}
}
}
}
The list view of the objects:
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")
}
}
}
}
}
The detail view:
struct ObjectsDetailView : View {
@Binding var myObject: MyObject
var body: some View {
Text("\(myObject.title)")
}
}
So the problem is quite complex.
- The
ObjectsListView
creates instance of theMyObject(store: myObjectsStore)
on itself initialization while computingbody
. - The
MyObject
object is setting itsstore
property on itself initialization, since it should know is it belongs tomyObjectsStore
or toanotherMyObjectsStore
. - The
myObjectsStore
are @BindableObjects since their changes are managing by SwiftUI itself.
So this behavior ends up that I've unexpected MyObject()
initializations since the Views are computing itself. Like:
- First
MyObject
creates on theObjectsListView
initialization. - Second
MyObject
creates on itsPresentationButton
pressing (the expected one). - Third (any sometimes comes even fourth)
MyObject
creates on dismissingObjectsDetailView
.
So I can't figure what pattern should I use this case to create only one object?
The only thing that I'd come to is to make the follow code:
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")
}
}
}
}
}
}
Which simply redraw ObjectsListView
to detail view conditionally. But it's completely out of iOS guidelines. So how to create the Only One object for another view in SwiftUI?
UPD: Here's the project that represents the bug with Object duplication. I'm still have no idea why the objects are duplicating in this case. But at least I know the reason yet. And the reason is this line:
@Environment(\.myObjectsStore.objects) var myObjectsStores: Places
I've tried to share my model with this wrapper to make it available in every single view (including Modal one) without passing them as an arg to the new view initializer, which are unavailable by the other ways, like @EnvironmentObject
wrapper. And for some reason @Environment(\.keyPath)
wrapper makes duplications.
So I'd simply replace all variables from Environment(\.)
to ObjectBinding
and now everything works well.