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 } } } }
2. 列表页简化NavigationLink
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
相关产品推荐
相关产品推荐

