You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift:如何在单个View中传递并使用两个不同的数据模型结构体?

解决列表页向详情页传递Firestore共享集合CareData的问题

核心问题在于你当前的ViewModel用数组存储careData,无法直接关联到对应的Items实例。下面提供两种可行的解决方案:

方案一:用字典缓存CareData,列表页直接传递对应实例

1. 修改ViewModel的存储结构

把careData数组改为字典,用item.name作为key,这样可以快速查找每个Item对应的CareData:

class ViewModel: ObservableObject {
    @Published var itemList = [Items]()
    // 替换数组为字典,key是item的name,value是对应的CareData
    @Published var careDataDict = [String: CareData]()

    // 获取Item列表的函数示例
    func fetchItems() {
        // 原有的Firestore查询itemList的代码...
        // 获取到itemList后,预加载每个item对应的CareData
        for item in itemList {
            getCareData(itemName: item.name)
        }
    }

    func getCareData(itemName: String) {
        let db = Firestore.firestore()
        db.collection("你的共享集合名称").document(itemName).getDocument { snapshot, error in
            guard let data = snapshot?.data(), error == nil else { return }
            
            // 解析Firestore数据到CareData
            let avHeight = data["avHeight"] as? Int ?? 0
            let avWater = data["avWater"] as? Int ?? 0
            
            DispatchQueue.main.async {
                // 存入字典缓存
                self.careDataDict[itemName] = CareData(avHeight: avHeight, avWater: avWater)
            }
        }
    }
}

2. 列表页NavigationLink传递数据

在列表循环中,通过item.name从字典中取出对应CareData,用默认值兜底避免可选值问题:

List(model.itemList) { item in
    NavigationLink(
        destination: Detail(
            item: item,
            // 从字典取对应数据,没有则用默认值
            care: model.careDataDict[item.name] ?? CareData(avHeight: 0, avWater: 0)
        )
    ) {
        Text(item.name)
    }
    // 页面出现时检查数据是否存在,不存在则加载
    .onAppear {
        if model.careDataDict[item.name] == nil {
            model.getCareData(itemName: item.name)
        }
    }
}

方案二:详情页自行加载对应CareData(无需列表页传递)

如果不想在列表页处理数据关联,可以让详情页根据传入的Item自行加载CareData,这样列表页只需要传递Item:

1. 修改详情页代码

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

    let item: Items
    // 用@State存储当前详情页的CareData
    @State private var care: CareData = CareData(avHeight: 0, avWater: 0)

    var body: some View {
        VStack {
            Text("Item Name: \(item.name)")
            Text("Average Height: \(care.avHeight)")
            Text("Average Water: \(care.avWater)")
        }
        .onAppear {
            loadCareData()
        }
    }

    private func loadCareData() {
        // 先检查ViewModel的缓存,避免重复请求
        if let cachedCare = model.careDataDict[item.name] {
            care = cachedCare
            return
        }

        // 从Firestore加载数据
        let db = Firestore.firestore()
        db.collection("你的共享集合名称").document(item.name).getDocument { snapshot, error in
            guard let data = snapshot?.data(), error == nil else { return }
            
            let avHeight = data["avHeight"] as? Int ?? 0
            let avWater = data["avWater"] as? Int ?? 0
            
            DispatchQueue.main.async {
                care = CareData(avHeight: avHeight, avWater: avWater)
                // 存入ViewModel缓存,其他页面复用
                model.careDataDict[item.name] = care
            }
        }
    }
}
List(model.itemList) { item in
    NavigationLink(destination: Detail(item: item)) {
        Text(item.name)
    }
}

原错误原因说明

你之前遇到的Cannot convert value of type 'CareData.Type' to expected argument type 'CareData'错误,是因为你尝试传递CareData类型本身(比如直接写care: CareData),而不是传递一个CareData的实例。通过上述方案,我们确保传递的是对应Item的具体CareData实例,解决了类型不匹配的问题。

内容的提问来源于stack exchange,提问作者user19351421

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 14:25:29