Home > Blockchain >  SwiftUI: How to prevent view from dismissing after updating the array
SwiftUI: How to prevent view from dismissing after updating the array

Time:10-25

I am making app where I have to be able to modify/delete data. I am using firebase so the original structure is more complex, but to show my problem I created test views. I am having hard time debugging issue with view dismissing itself. After deleting one item of nested array, it's dismissing my view, and I am not sure how to prevent that.

This is my model:

struct Object: Identifiable {
    var id = UUID()
    var name: String
    var nestedObjects: [NestedObject]
}
struct NestedObject: Identifiable {
    var id = UUID()
    var name: String
}

This is my View Model:

class ViewModel: ObservableObject {
    @Published var objects = [
        Object(name: "1", nestedObjects: [
            NestedObject(name: "1.1"),
            NestedObject(name: "1.2"),
            NestedObject(name: "1.3"),
            NestedObject(name: "1.4"),
        ]),
        Object(name: "2", nestedObjects: [
            NestedObject(name: "2.1"),
            NestedObject(name: "2.2"),
            NestedObject(name: "2.3"),
            NestedObject(name: "2.4"),
        ])
    ]
}

Content View:

struct ContentView: View {
    @StateObject var vm = ViewModel()
    var body: some View {
        NavigationView {
            List(vm.objects){ object in
                NavigationLink {
                    SubView(object: object)
                } label: {
                    Text(object.name)
                }

            }
        }.environmentObject(vm)

    }
}

And Nested View:

struct SubView: View {
    let object: Object
    @EnvironmentObject var vm: ViewModel
    var body: some View {
        List(object.nestedObjects) { nested in
            HStack {
                Text(nested.name)
                Spacer()
                Button {
                    let array = object.nestedObjects.filter({$0.id != nested.id})
                    vm.objects = vm.objects.filter({$0.id != object.id})
                    vm.objects.append(Object(name: object.name, nestedObjects: array))
                } label: {
                    Image(systemName: "trash.fill")
                }.buttonStyle(.borderless)

            }
        }
    }
}

I really want the structure to stay because I know that I am overdoing here in this example but in main project I have Firestone listener and after reaching which object is modified I have to change him, and that's when it's being dismissed.

CodePudding user response:

The problem is happening because NavigationLink depends on the Object id. When you create a new Object by doing Object(name: object.name, nestedObjects: array), it has a new and different id because of your definition of id: var id = UUID()

One solution would be to make a copy of the Object, replace the nested values, and then map it back into the original array.

Note that this might be even easier if you chose to structure your Objects in a Dictionarykeyed byid` rather than an array, but that's certainly optional.

struct SubView: View {
    let object: Object
    @EnvironmentObject var vm: ViewModel
    var body: some View {
        List(object.nestedObjects) { nested in
            HStack {
                Text(nested.name)
                Spacer()
                Button {
                    var copy = object
                    copy.nestedObjects = object.nestedObjects.filter { $0.id != nested.id }
                    vm.objects = vm.objects.map { $0.id == copy.id ? copy : $0 }
                } label: {
                    Image(systemName: "trash.fill")
                }.buttonStyle(.borderless)

            }
        }
    }
}
  • Related