0

It seems that DetailView is only hidden and not removed from the screen, which means that the .onDisappear event is not being triggered for the same view, but is triggered between views. How to achieve a correct logic without moving DetailView outside of ForEach loop?

struct TestItem: Identifiable, Hashable {
    let id = UUID()
    let name: String
}

let items: [TestItem] = [TestItem(name: "Name 1"), TestItem(name: "Name 2"), TestItem(name: "Name 3")]

struct ContentView: View {
    @State var selectedItem: TestItem? = nil
    @State var detailViewPresented: Bool = false
    
    var body: some View {
        List {
            ForEach(items) { item in
                VStack(alignment: .leading) {
                    Text(item.name)
                }
                .onTapGesture {
                    if selectedItem == item && detailViewPresented {
                        detailViewPresented = false
                    } else {
                        detailViewPresented = true
                    }

                    selectedItem = item
                }

                if selectedItem == item && detailViewPresented {
                    DetailView(item: item)
                }
            }
        }
    }
}

struct DetailView: View {
    let item: TestItem

    var body: some View {
        VStack {
            Text("Detail View")
            Text(item.name)
        }
        .onDisappear {
            print("DetailView Disappeared")
        }
    }
}

Here's a link with an example of the problem.

netsplatter
  • 559
  • 3
  • 14
  • Why not just watch the values of `detailViewPresented` or `selectedItem`? – jnpdx Apr 20 '23 at 00:34
  • detailViewPresented and selectedItem are being watched in the example. Could your explain you suggestion in more detail? – netsplatter Apr 20 '23 at 19:31
  • `.onChange(of: detailViewPresented) { newValue in print("Presented?", newValue) }` instead of using `onDisappear` – jnpdx Apr 20 '23 at 19:32
  • Because I need DetailView to be completely invalidated every time it disappears. Otherwise, in more complex environment, it will crash the app. – netsplatter Apr 20 '23 at 19:35
  • It might be helpful if you include an example that represents the issue. – jnpdx Apr 20 '23 at 20:40
  • It's complicated. I'm having a problem with CoreData - I don't know how to invalidate a view when deleting an item from database. I have a list of views, received from FetchedResults, and each item has DetailView which uses item as StateObject. After I delete item inside DetailView using managedObjectContext?.delete(item), it may crash that supposedly deleted view later, referring to some binded data in that view. The view is supposed to be invalidated right on the moment of deletion. If you would like to go further, I can recreate this problem. – netsplatter Apr 24 '23 at 04:46
  • @jnpdx, I created an example that represents the issue in more detail - https://stackoverflow.com/questions/76186560/how-to-prevent-swiftui-detailview-from-crashing-when-deleting-the-last-entity-fr – netsplatter May 06 '23 at 00:09

0 Answers0