Hardy
Hardy

Reputation: 4796

.sheet: Shows only once and then never again

Working with Beta4, it seems that the bug is still existing. The following sequence of views (a list, where a tap on a list entry opens another list) allows to present the ListView exactly once; the onDisappear is never called, so the showModal flag changes, but does not triggers the redisplay of ListView when tapped again. So, for each GridCellBodyEntry, the .sheet presentation works exactly once, and then never again.

I tried around with several suggestions and workarounds, but none worked (e.g., encapsulating with a NavigationViewModel). I even tried to remove the List, because there was an assumption that the List causes that behaviour, but even this did not change anything.

Are there any ideas around?

The setup:

  1. A GridCellBody with this view:
var body: some View {

        GeometryReader { geometry in

            VStack {

                List {

                    Section(footer: self.footerView) {

                        ForEach(self.rawEntries) { rawEntry in

                            GridCellBodyEntry(entityType: rawEntry)
                        }
                    }
                }
                .background(Color.white)
            }
        }
    }
  1. A GridCellBodyEntry with this definition:
struct GridCellBodyEntry: View {


    let entityType: EntityType
    let viewModel: BaseViewModel


    init(entityType: EntityType) {

        self.entityType = entityType
        self.viewModel = BaseViewModel(entityType: self.entityType)
    }


    @State var showModal = false {

        didSet {

            print("showModal: \(showModal)")
        }
    }


    var body: some View {

        Group {

            Button(action: {

                self.showModal.toggle()
            },
                   label: {

                    Text(entityType.localizedPlural ?? "")
                        .foregroundColor(Color.black)
            })
            .sheet(isPresented: $showModal, content: {

                ListView(showModal: self.$showModal,
                         viewModel: self.viewModel)
            })
        }.onAppear{
            print("Profile appeared")
        }.onDisappear{
            print("Profile disappeared")
        }
    }
}
  1. A ListView with this definition:
struct ListView: View {


    // MARK: - Private properties


    // MARK: - Public interface


    @Binding var showModal: Bool
    @ObjectBinding var viewModel: BaseViewModel


    // MARK: - Main view


    var body: some View {

        NavigationView {

            VStack {

                List {

                    Section(footer: Text("\(viewModel.list.count) entries")) {

                        ForEach(viewModel.list, id: \.objectID) { item in

                            NavigationLink(destination: ItemView(),
                                           label: {

                                            Text("\(item.objectID)")
                            })
                        }
                    }
                }
            }
            .navigationBarItems(leading:

                Button(action: {

                    self.showModal = false
                }, label: {

                    Text("Close")
                }))

            .navigationBarTitle(Text(viewModel.entityType.localizedPlural ?? ""))
        }
    }
}
  1. The BaseViewModel (excerpt):
class BaseViewModel: BindableObject {

    /// The binding support. 
    var willChange = PassthroughSubject<Void, Never>()

    /// The context.
    var context: NSManagedObjectContext

    /// The current list of typed items.
    var list: [NSManagedObject] = []

    // ... other stuff ...
}

where willChange.send() is called whenever something changes (create, modify, delete operations).

Upvotes: 5

Views: 1122

Answers (1)

Zain
Zain

Reputation: 1679

This is a variant of swiftUI PresentaionLink does not work second time

The following simplified code exhibits the behavior you're experiencing (the sheet only displays once):

import SwiftUI

struct ContentView: View {
    @State var isPresented = false
    @State var whichPresented = -1

    var body: some View {
        NavigationView {
            List {
                ForEach(0 ..< 10) { i in
                    Button(action: {
                            self.whichPresented = i
                            self.isPresented.toggle()
                        })
                        { Text("Button \(i)") }
                    }.sheet(isPresented: $isPresented, content: { 
Text("Destination View \(self.whichPresented)") })
                }
            }
    }
}

There appears to be a bug in SwiftUI when you put the .sheet inside a List or a ForEach. If you move the .sheet outside of the List, you should be able to get the correct behavior.

import SwiftUI

struct ContentView: View {
    @State var isPresented = false
    @State var whichPresented = -1

    var body: some View {
        NavigationView {
            List {
                ForEach(0 ..< 10) { i in
                    Button(action: {
                            self.whichPresented = i
                            self.isPresented.toggle()
                        })
                        { Text("Button \(i)") }
                    }
                }
            }.sheet(isPresented: $isPresented, content: { Text("Destination View \(self.whichPresented)") })
    }
}

Upvotes: 3

Related Questions