0
votes

This is my first SwiftUI project and am very new in programming.

I have a View Model and a picker for my Content View, manage to send $selection to Detail View but not sure how to get it to read from the Firestore again. I kinda feel like something is missing, like I need to use an if-else, but can't pinpoint exactly what is the problem. Searched through the forum here but can't seemed to find a solution.

Here is the VM

import Foundation
import Firebase

class FoodViewModel: ObservableObject {

@Published var datas = [Food]()

private var db = Firestore.firestore()

func fetchData(){
    
    db.collection("meals").addSnapshotListener { (snap, err) in
        DispatchQueue.main.async {
        if err != nil {
            print((err?.localizedDescription)!)
            return
        } else {
        for i in snap!.documentChanges{
                
                let id = i.document.documentID
                let name = i.document.get("name") as? String ?? ""
                let weight = i.document.get("weight") as? Int ?? 0
                let temp = i.document.get("temp") as? Int ?? 0
                let time = i.document.get("time") as? Int ?? 0
                
                
                self.datas.append(Food(id: id, name: name, weight: weight, temp: temp, time: time))
            }
        }
        }
    }
}

}

struct ContentView: View {

@ObservedObject var foodDatas = FoodViewModel()

@State private var id = ""
@State public var selection: Int = 0

var body: some View {
    
    NavigationView{

        let allFood = self.foodDatas.datas

        ZStack {
            Color("brandBlue")
                .edgesIgnoringSafeArea(.all)
            VStack {
                Picker(selection: $selection, label: Text("Select your food")) {
                    ForEach(allFood.indices, id:\.self) { index in
                        Text(allFood[index].name.capitalized).tag(index)
                    }
                }
                .onAppear() {
                    self.foodDatas.fetchData()
                }

                Spacer()
                
                NavigationLink(
                    destination: DetailView(selection: self.$selection),
                    label: {
                        Text("Let's make this!")
                            .font(.system(size: 20))
                            .fontWeight(.bold)
                            .foregroundColor(Color.black)
                            .padding(12)
                    })
}

And after the picker selected a food type, I hope for it to display the rest of details such as cooking time and temperature. Now it is displaying 'index out of range' for the Text part.

import SwiftUI
import Firebase

struct DetailView: View {

@ObservedObject var foodDatas = FoodViewModel()

@Binding var selection: Int


var body: some View {
    
    NavigationView{
        
        let allFood = self.foodDatas.datas
        
        ZStack {
            Color("brandBlue")
                .edgesIgnoringSafeArea(.all)
            VStack {
                
                Text("Cooking Time: \(allFood[selection].time) mins")
                
            }

        }

    }
}

Appreciate for all the help that I can get.

1

1 Answers

0
votes

In your DetailView, you're creating a new instance of FoodViewModel:

@ObservedObject var foodDatas = FoodViewModel()

That new instance has not fetched any data, and thus the index of the selection is out of bounds, because it's array is empty.

You could pass your original ContentView's copy of the FoodDataModel as a parameter.

So, the previous line I quoted would become:

@ObservedObject var foodDatas : FoodViewModel

And then your NavigationLink would look like this:

NavigationLink(destination: DetailView(foodDatas: foodDatas, selection: self.$selection) //... etc