MVVM项目中如何从Firebase返回数组并正确存储到变量
针对你的两个MVVM+Firebase数据返回问题的解决方案
咱们先从第一个核心问题说起:如何正确返回异步数据并存储到变量中
Firebase的数据库/存储操作都是异步执行的——也就是说,当你调用getFirebaseData这类方法时,代码不会等待网络请求完成就继续往下走了。如果直接尝试同步返回数据,你大概率会拿到空数组,因为数据还没从服务器拉回来。
正确的做法是用**闭包(Completion Handler)**或者Combine框架来处理异步回调,等数据真正准备好之后再把它传递给调用者并存储到变量里。闭包是最直观的方案,尤其适合刚迁移到MVVM的场景。
接下来针对你的第二个具体场景:把仓库类中Firebase循环生成的数组返回给MyCollectionViewClass
我会给你一步步的代码示例,贴合你已经有的结构:
第一步:修改仓库类的getFirebaseData方法,添加闭包参数
首先在你的Firebase仓库类里,把原来的方法改成带闭包的形式,闭包用来返回最终的[Recipe]数组:
class FirebaseReference { // 假设这是你的仓库类 func getFirebaseData(with stringParam: String, completion: @escaping ([Recipe]) -> Void) { // 这里是你的Firebase查询逻辑,比如从Firestore获取数据 let db = Firestore.firestore() db.collection("your-collection-path").whereField("someField", isEqualTo: stringParam).getDocuments { snapshot, error in guard let documents = snapshot?.documents, error == nil else { print("获取数据失败:\(error?.localizedDescription ?? "未知错误")") completion([]) // 出错时返回空数组,也可以根据需求返回错误信息 return } var recipeArray = [Recipe]() // 遍历Firebase返回的文档,生成Recipe数组 for doc in documents { if let recipe = try? doc.data(as: Recipe.self) { // 假设Recipe实现了Codable recipeArray.append(recipe) } } // 数据准备好后,通过闭包返回 completion(recipeArray) } } }
第二步:在MyCollectionViewClass中调用方法并存储数据
在你的MyCollectionViewClass里,调用仓库方法时,通过闭包拿到返回的数组,赋值给imageArray,然后刷新CollectionView:
class MyCollectionViewClass: UICollectionViewController { var imageArray = [Recipe]() let firebaseReference = FirebaseReference() // 初始化仓库类实例 override func viewDidLoad() { super.viewDidLoad() // 调用仓库的方法,传入参数并处理返回数据 firebaseReference.getFirebaseData(with: self.dataRecieverStringCollectionView) { [weak self] fetchedRecipes in guard let self = self else { return } // 将返回的数组存储到变量中 self.imageArray = fetchedRecipes // 刷新CollectionView,因为数据源更新了 self.collectionView.reloadData() } } // 其他CollectionView数据源方法... override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return imageArray.count } override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCellID", for: indexPath) as! YourCellClass let recipe = imageArray[indexPath.item] // 用recipe配置cell的UI... return cell } }
关键注意点
- 用
[weak self]避免循环引用:在闭包中捕获self时,加上弱引用可以防止内存泄漏,这在ViewController中尤其重要。 - 处理错误情况:示例中出错时返回空数组,你也可以把闭包改成
@escaping (Result<[Recipe], Error>) -> Void,这样能更优雅地传递错误信息,调用者可以通过switch处理成功和失败的情况。 - 确保
Recipe模型实现Codable:Firestore的doc.data(as:)方法需要模型遵守Codable协议,这样才能自动解析文档数据到模型对象中。
内容的提问来源于stack exchange,提问作者Joakim Sjöstedt
相关产品推荐
相关产品推荐

