0

I have an HStack in a NavigationView with the following design:

  1. User can scroll, then tap an item from the HStack list to see details
  2. On Detailed View user can select the item
  3. if item is selected, I place a new view of the selected item on top of the HStack so only the selected item is visible
  4. I want to leave the original HStack and list underneath the new view so the user can reverse the flow and not lose scroll position

I have done this using some test data and it works as expected, however when I use data from a Firebase call the original HStack/List view is dismissed when the new "selected" view is placed on top... and I can't understand why. I think it may have to do with how the observed object is initiated. Help is appreciated!

struct TestView: View {
@StateObject var selectedItem = SelectedItem()

//Real Query
@ObservedObject var query = Query()

@ObservedObject var testQuery = TestQuery()

var body: some View {
    VStack{
        ZStack{
            ScrollView(.horizontal) {
                HStack(spacing: 35) {

                    //ForEach(query.queriedList) doesn't work, however the below does...

                    ForEach(testQuery.testList) { menuItems in
                        NavigationLink(
                            destination: NewDetailView(selectedItem: selectedItem, weeklyItems: weeklyItems, menuItem: menuItems)) {
                            MenuItemView(menuItem: menuItems)
                                .padding([.leading, .trailing])
                        }
                    }
                }
            }
            //if the array is NOT empty
            if selectedItem.selection.isEmpty == false {
                
                //PUT THIS ON TOP
                ScrollView(.horizontal) {
                    NavigationLink(
                        destination: NewDetailView(selectedItem: selectedItem, weeklyItems: weeklyItems, menuItem: self.selectedItem.selection[0], isSelected: true)) {
                            MenuItemView(menuItem: self.selectedItem.selection[0])
                            .padding([.leading, .trailing])
                    }
                }
            }
        }
    }
}

What the Test Query looks like

class TestQuery: ObservableObject {

@Published var testList: [MenuItem] = [.init(title: "Ham & Eggs", prepTime: 5, cookTime: 5, rating: 2, lastUsed: 13), .init(title: "Hot Totters", prepTime: 5, cookTime: 5, rating: 2, lastUsed: 13), .init(title: "Ranch Dressing Soup", prepTime: 5, cookTime: 5, rating: 2, lastUsed: 13)]
}

The Firebase Query

class Query: ObservableObject {

@Published var queriedList: [MenuItem] = []

init() {
    baseQuery()
}

func baseQuery() {
  let queryRef1 = Firestore.firestore().collection("menuItems").limit(to: 50)
    print("base fired")
    queryRef1
        .getDocuments() { (querySnapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
        } else {
            self.queriedList = querySnapshot?.documents.compactMap { document in
                try? document.data(as: MenuItem.self)
                
            } ?? []
        }
    }
}
TJMac
  • 129
  • 1
  • 12
  • 1
    Change the two observed objects to state objects – lorem ipsum Oct 13 '21 at 07:48
  • Thank you! Hard to believe I spent as much time as I did trying to work that through. Appreciate you pointing that out. Feel free to post an answer and I'll accept. – TJMac Oct 13 '21 at 18:35

1 Answers1

3

The only safe way to create an ObservableObject in a SwiftUI View is using

@StateObject

Switch the two ObservedObjects to StateObjects

https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app

lorem ipsum
  • 21,175
  • 5
  • 24
  • 48