1

Below is a simple representation of what I am trying to achieve in my own (much larger) application. This example has 3 Views:

  1. ItemsView - displaying [Item]
  2. DetailView - The selected Item with an option to edit the Item
  3. EditView - Edit the selected Item or delete if required

Users select an Item from the list, it is viewed in the DetailView and should they wish, they can change the Item text in EditView. Should they want to delete the Item, the option is available within the EditView.

Everything works as it should when editing and deleting the object, however when the sheet dismisses itself (as it should through dismiss()) and we return to the DetailView, it still shows the selected Item, even though the item has now been removed from the observed class array Items.allItems

How can I get both the sheet and DetailView to dismiss themselves when pressing delete in the EditView returning the user back to the ItemsView?

I've tried popping, paths, bindings - all sorts. With each attempt it just becomes a mess and fails to work. I'm hoping someone can provide a logical explanation to what should be an easy task.

Here's the code, thank you.

struct Item: Identifiable, Hashable {
    var id = UUID().uuidString
    var title: String
}
class Items: ObservableObject {
    @Published var allItems = [
    Item(title: "Apple"),
    Item(title: "Boat"),
    Item(title: "Car"),
    Item(title: "Drink")
    ]
}
struct ItemsView: View {
    @EnvironmentObject var items: Items
    var body: some View {
        NavigationStack {
            List {
                ForEach($items.allItems) { $item in
                    NavigationLink {
                        DetailView(item: $item)
                    } label: {
                        Text(item.title)
                    }
                }
            }
            .navigationTitle("Items")
        }
    }
}
struct DetailView: View {
    @Binding var item: Item
    @Environment(\.dismiss) var dismiss
    @State private var isEditViewShowing = false
    var body: some View {
        VStack {
            Text(item.title)
        }
        .sheet(isPresented: $isEditViewShowing, content: {
            NavigationStack {
                EditView(item: $item)
            }
        })
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                Button("Edit") {
                    isEditViewShowing = true
                }
            }
        }
    }
}
struct EditView: View {
    @EnvironmentObject var items: Items
    @Environment(\.dismiss) var dismiss
    @Binding var item: Item
    var body: some View {
        Form {
            TextField("New", text: $item.title)
            Button("Delete") {
                items.allItems.removeAll {
                    $0.id == item.id
                }
                dismiss()
            }
        }
        .navigationTitle("Edit View")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                Button("Save") {
                    dismiss()
                }
            }
        }
    }
}
OxfordSi
  • 199
  • 1
  • 3
  • 14
  • Look into https://www.hackingwithswift.com/quick-start/swiftui/whats-the-difference-between-observedobject-state-and-environmentobject. @ObservedObject will be a better use case here – Harry J May 29 '23 at 04:10

0 Answers0