类 Observable 对象 @Published 变量始终为空

Posted

技术标签:

【中文标题】类 Observable 对象 @Published 变量始终为空【英文标题】:Class Observable object @Published variable always empty 【发布时间】:2020-09-14 13:49:06 【问题描述】:

我正在尝试从 firebase firestore 获取集合。下面是我的 ViewModel 我无法将数据存储在 @Published var 类别对象中。我无法找到确切的问题,我对 swift 有点陌生,但前一段时间完全相同的事情正在工作,我做错了什么吗?

FormViewModel.swift

import Firebase
import FirebaseFirestore

class FormViewModel: ObservableObject 
    @Published var categories = [Category]()
    private var db = Firestore.firestore()
    
    func fetchCategories() 
        db.collection("companies_by_category").addSnapshotListener  (QuerySnapshot, error) in
            guard let documents = QuerySnapshot?.documents else 
                print("No documents")
                return
            

            self.categories = documents.compactMap  (QueryDocumentSnapshot) -> Category? in
                return try? QueryDocumentSnapshot.data(as: Category.self)
            
            print(self.categories) // -> Able to get data
        
    

我的分类视图

struct CategoriesView: View 
    
    @ObservedObject var viewmodel = FormViewModel()
    
    var body: some View 
        ScrollView 
            List(self.viewmodel.categories)  category in
                ZStack 
                    RoundedRectangle(cornerRadius: 15, style: .continuous)
                        //.foregroundColor(category.selected == true ? Color.yellow.opacity(0.5) : Color.white)
                        .foregroundColor(.white)
                        .shadow(color: Color.black.opacity(0.1), radius: 10, x: 0, y: 0)
                    
                    VStack(spacing: 20) 
                        HStack 
                            Image("\(category.category)")
                                .foregroundColor(Color.gray)
                                .font(.system(size: 20.0))
                            Text(category.category)
                                .font(.system(size: 20.0, weight: .medium))
                                .foregroundColor(Color.black)
                            Spacer()
                        
                    
                .padding()
                
            
        
        .onAppear() 
            self.viewmodel.fetchCategories()
        
    

【问题讨论】:

这是因为您正在对数据库进行异步调用,因此在返回数据之前执行打印。由于categories 已发布,因此您不必担心这一点,因此当数组获取值时,任何观察者都会收到通知。 programmingios.net/what-asynchronous-means 谢谢我错过了它是异步的事实,但正如大卫在答案中解释的那样,问题不在于@Published,而在于@observed 对象,因为我在视图本身中创建它。 【参考方案1】:

您错过了 addSnapshotListener 是一个异步函数的事实。您的第二次打印不会返回任何数据,因为它会在addSnapshotListener 的异步网络请求返回任何数据之前同步执行。你只能在函数的闭包内访问addSnapshotListener的异步数据。

但是,您的实际视图未更新的原因与上述不同。您正在从异步闭包内部正确更新 categories 数组,因此每当异步请求完成时,您的 categories 将包含正确的数据。

UI 问题来自您在视图中创建 @ ObservedObject 属性这一事实。这是完全不正确的,因为每当 View@ObservedObject 属性更新时,视图将被重绘,这将导致其属性也被重新计算。您可以通过在视图的 init 中注入您的视图模型来解决此问题。查看this answer 以获取有关如何将@ObservedObjects 注入Views 的更详细说明。

【讨论】:

嘿感谢您的回答,即使在主视图中将其初始化为 - `MainView - @State var formViewModel = FormViewModel() CategoriesView(viewModel: self.formViewModel) ` CategoriesView - `@ObserverdObject var viewmodel: FormViewModel ` @RahulBajaj 你试过调试你的代码吗? categories 是否实际更新并包含元素?如果在CategoriesViewbody 中下断点,在categories 更新后会被命中吗?

以上是关于类 Observable 对象 @Published 变量始终为空的主要内容,如果未能解决你的问题,请参考以下文章

Java中使用Observer接口和Observable类实践Observer观察者模式

我们什么时候应该使用Observer和Observable?

如何以角度将 JSON 对象数组转换为 Observable 数组

Angular 7 - 对象的 Observables 数组的 Observable 数组

Infinite Observable 到 HashMap 作为 Observable

如何在 Angular 中管道/映射 Observable