如何将会议ID从View传入ViewModel以查询Firebase子集合
解决方案:将会议ID传入ViewModel查询Firebase子集合
针对你遇到的问题,核心是把已获取的meetingId传递给ViewModel,用于查询对应子集合数据。下面提供两种直接可行的实现方案:
方案一:初始化ViewModel时传入会议ID
这种方式最直接,在创建ViewModel时就把会议ID注入,ViewModel可以立即开始获取子集合数据。
1. 修改MeetingViewModel,添加带参数的初始化方法
class MeetingViewModel: ObservableObject { @Published var breakouts: [Breakout] = [] @Published var tours: [Tour] = [] private var currentMeetingId: String? // 支持传入会议ID的初始化方法 init(meetingId: String? = nil) { self.currentMeetingId = meetingId // 如果有会议ID,初始化时自动拉取子集合数据 if let id = meetingId { Task { try await fetchSubCollections(for: id) } } } // 拉取指定会议的子集合数据 func fetchSubCollections(for meetingId: String) async throws { // 查询breakouts子集合 let breakoutsSnapshot = try await Firestore.firestore() .collection("meetings") .document(meetingId) .collection("breakouts") .getDocuments() self.breakouts = breakoutsSnapshot.documents.compactMap { try? $0.data(as: Breakout.self) } // 查询tours子集合 let toursSnapshot = try await Firestore.firestore() .collection("meetings") .document(meetingId) .collection("tours") .getDocuments() self.tours = toursSnapshot.documents.compactMap { try? $0.data(as: Tour.self) } } // 保留原有fetchAllMeetings方法 func fetchAllMeetings() async throws { // ... 原有逻辑 } }
2. 修改目标视图LongProductsView,传入会议ID初始化ViewModel
struct LongProductsView: View { @StateObject var viewModel: MeetingViewModel @State private var showNewMeetingView = false @State private var showMeeting = false @Environment(\.dismiss) var dismiss var meet: Meeting // 自定义初始化方法,接收会议对象并传入ViewModel init(meet: Meeting) { self.meet = meet self._viewModel = StateObject(wrappedValue: MeetingViewModel(meetingId: meet.id)) } var body: some View { VStack { Text(meet.title) Text(meet.datestart) // 示例:展示breakouts子集合数据 List(viewModel.breakouts) { breakout in Text(breakout.name) } } .toolbar{ ToolbarItem(placement: .navigationBarLeading) { Button(action: { dismiss() }) { Image(systemName: "arrowshape.turn.up.backward") .font(.footnote) .foregroundColor(.blue) } .padding(.vertical) } } } }
方案二:在视图出现时传递会议ID给ViewModel
如果不想修改ViewModel的初始化逻辑,可以在视图onAppear时调用ViewModel的方法,传入会议ID并触发数据拉取。
1. 修改MeetingViewModel,添加设置会议ID并拉取数据的方法
class MeetingViewModel: ObservableObject { @Published var breakouts: [Breakout] = [] @Published var tours: [Tour] = [] private var currentMeetingId: String? // 设置会议ID并拉取对应子集合数据 func setMeetingAndFetchData(_ meetingId: String) async throws { // 避免重复请求同一会议的数据 guard currentMeetingId != meetingId else { return } currentMeetingId = meetingId try await fetchBreakouts(for: meetingId) try await fetchTours(for: meetingId) } private func fetchBreakouts(for meetingId: String) async throws { let snapshot = try await Firestore.firestore() .collection("meetings") .document(meetingId) .collection("breakouts") .getDocuments() self.breakouts = snapshot.documents.compactMap { try? $0.data(as: Breakout.self) } } private func fetchTours(for meetingId: String) async throws { let snapshot = try await Firestore.firestore() .collection("meetings") .document(meetingId) .collection("tours") .getDocuments() self.tours = snapshot.documents.compactMap { try? $0.data(as: Tour.self) } } // 保留原有fetchAllMeetings方法 func fetchAllMeetings() async throws { // ... 原有逻辑 } }
2. 修改目标视图,在onAppear时调用方法
struct LongProductsView: View { @StateObject var viewModel = MeetingViewModel() @State private var showNewMeetingView = false @State private var showMeeting = false @Environment(\.dismiss) var dismiss var meet: Meeting var body: some View { VStack { Text(meet.title) Text(meet.datestart) List(viewModel.breakouts) { breakout in Text(breakout.name) } } .toolbar{ ToolbarItem(placement: .navigationBarLeading) { Button(action: { dismiss() }) { Image(systemName: "arrowshape.turn.up.backward") .font(.footnote) .foregroundColor(.blue) } .padding(.vertical) } } .onAppear { Task { try await viewModel.setMeetingAndFetchData(meet.id) } } } }
额外注意事项
- 如果需要实时监听子集合数据变化,可以将
getDocuments()替换为addSnapshotListener,实现数据实时同步 - 建议在ViewModel中添加
@Published var error: Error?属性,用于捕获并在视图中展示异步请求的错误 - 确保Firebase的安全规则允许当前用户访问指定会议的子集合数据
内容的提问来源于stack exchange,提问作者johnny
相关产品推荐
相关产品推荐

