Home > Blockchain >  Swift: (How) Can I use two different Data Model Structs in one View?
Swift: (How) Can I use two different Data Model Structs in one View?

Time:10-28

I have a UI with a list of items that the user can tap. This opens a detail view listing all details for one item. However, I want to include 2 values in that detail view that are stored in a different collection in Firestore and that also have their own Data Model struct. The reason for this is that a different app works with that collection and I want to separate "shared" collections from the rest.

I got a function that is pulling these 2 values from Firestore done
This function is passing the values to a struct called CareData in my Data Model done
I think I set up everything correctly in the detail view, but the problem is passing that data from the tabable list to the detail view.

Let me try to explain what I did with my code:

Data Model
Just simple arrays, nothing complex.

struct Items: Decodable, Identifiable {
    var id: String
    var name: String
    …
}

struct CareData {
    var avHeight: Int
    var avWater: Int
}

Detail View

struct Detail: View {
    @EnvironmentObject var model: ViewModel
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>        

    // Passing the model instances
    let item: Items
    let care: CareData

    var body: some View {
        // Some (working) code where data like item.name is shown.
        ...
        
        // The 2 values using the CareData Data Model
        Text("Height: \(care.avHeight)")
        Text("Water: \(care.avWater)")
    }
}

View Model
An important note here: The documents in my shared collection are named after the item name of the not shared collection. When I call the function, I use item.name to query to the correct document in the shared collection.

class ViewModel: ObservableObject {
    @Published var itemList = [Items]()
    @Published var careData = [CareData]()

    ...
    func getCareData(item: String) {
        // Some code that gets the data in Firestore from the shared collection and appends it to careData. It is working all well.
    }
}

Problematic List View
Detail() in the NavigationLink is expecting me to pass 2 parameters because I am trying to pass both model instances in the Detail View. I understand to use item: item, as I am looping through all items and need to define what is needed for the Detail View. But what do I need to add for care:?

struct PlantList: View {
    @EnvironmentObject var model: ViewModel

    var body: some View {
        ForEach(model.itemList) { item in
            NavigationLink(destination: Detail(item: item, care: ?????? )) { // XCode proposing to go for "CareData", but then throws the error "Cannot convert value of type 'CareData.Type' to expected argument type 'CareData'"
                Text(item.name)
            }
            .onAppear {
                model.getCareData(item: item.name)
            }
        }
    }
}

I tried weird things like CareDate.init(avHeight: , avWater:) and it worked when I wrote numbers straight into the code, but I need the variables to be there not some static numbers I came up with.

I hope someone can help. All I want is to show the 2 values in the detail view. This is probably a stupid issue, but I'm frustrated as I seem to not understand the very basics of Swift programming yet.

CodePudding user response:

try something like this (untested of course, since I don't have your database), if you only ever want the first element:

EDIT-1: update

struct PlantList: View {
    @EnvironmentObject var model: ViewModel
 
    var body: some View {
        ForEach(model.itemList) { item in
            NavigationLink(destination: Detail(item: item, care: model.careData.first ?? CareData(avHeight: 0, avWater: 0))) {
                Text(item.name)
            }
            .onAppear {
                model.getCareData(item: item.name)
            }
        }
    }
}
  • Related