SwiftUI项目中无法将Firebase多集合拉取数据添加到新数组
问题原因
Firestore 的 addSnapshotListener 是异步执行的操作,你在视图的 onAppear 中按顺序调用三个拉取方法后直接执行 combineGames 时,Firebase 的网络请求还未完成,三个分类数组 cardsMenu/diceMenu/miscellaneuosMenu 还处于初始空值状态,合并后自然得到空数组。
最简解决方案
利用 Combine 框架自动监听三个分类数组的变化,自动合并生成 allGames,无需手动调用合并方法,适配实时数据更新的场景:
- 修改
SearchController代码:
import Foundation import SwiftUI import Firebase import Combine // 导入Combine框架 class SearchController: ObservableObject { @Published var allGames = [GameModel]() @Published var cardsMenu = [GameModel]() @Published var diceMenu = [GameModel]() @Published var miscellaneuosMenu = [GameModel]() private var db = Firestore.firestore() private var cancellables = Set<AnyCancellable>() // 存储订阅 init() { // 合并三个@Published属性的变化,自动生成allGames Publishers.CombineLatest3($cardsMenu, $diceMenu, $miscellaneuosMenu) .map { cardList, diceList, miscList in // 直接数组合并,不用循环append cardList + diceList + miscList } .assign(to: \.allGames, on: self) .store(in: &cancellables) } // 三个fetch方法保持原有代码不变 func fetchCardGamesData() {/*原有代码*/} func fetchDiceGamesData() {/*原有代码*/} func fetchMiscGamesData() {/*原有代码*/} // combineGames方法可以直接删除 }
- 修改视图
onAppear逻辑,删除手动合并调用:
.onAppear(){ self.allGames.fetchCardGamesData() self.allGames.fetchDiceGamesData() self.allGames.fetchMiscGamesData() // 移除 self.allGames.combineGames() 调用 }
- 可选优化:如果你的项目最低支持iOS 14+,将视图中
SearchController的声明从@ObservedObject改为@StateObject,避免视图重绘时对象被意外销毁导致数据丢失:
@StateObject var allGames = SearchController()
其他注意事项
如果不需要监听Firestore的实时数据变化,可以把 addSnapshotListener 替换为 getDocuments 只拉取一次数据,减少不必要的性能消耗和内存占用。
内容的提问来源于stack exchange,提问作者Nicolaj Spiegelhauer
相关产品推荐
相关产品推荐

