在onAppear中获取SwiftUI异步数据 [英] SwiftUI Async data fetch in onAppear

查看:162
本文介绍了在onAppear中获取SwiftUI异步数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类 getDataFromDatabase ,它具有可从Firebase读取数据的func readData().

I have class getDataFromDatabase which has func readData() thats read data from Firebase.

class getDataFromDatabase : ObservableObject {

    var arrayWithQuantity = [Int]()
    var arrayWithTime = [Double]()
    
    func readData(completion: @escaping(_ getArray: Array<Int>?,_ getArray: Array<Double>?) -> Void) {
       
        let db = Firestore.firestore()
        
        db.collection("amounts").getDocuments { (querySnapshot, err) in
            
            if let e = err{
                print("There's any errors: \(e)")
            }
            
            if err != nil{
                print((err?.localizedDescription)!)
                return
            }
            
            for i in querySnapshot!.documents{
                
                let quantityFromDb = i.get("amount") as! Int
                let timeFromDb = i.get("averageTimeRecognition") as! Double
                
                
                self.arrayWithQuantity.append(quantityFromDb)
                self.arrayWithTime.append(timeFromDb)
            }
            completion(self.arrayWithQuantity, self.arrayWithTime)
        }
    }
}

我在 onAppear 中使用func readData():

I use func readData() in onAppear:

struct CheckDatabaseView: View {
    
    @State private var quantityFromDatabase: Array<Int> = []
    @State private var timeFromDatabase: Array<Double> = []
    @State private var flowersName: Array<String> = ["Carnation", "Daisy", "Hyacinth", "Iris", "Magnolia", "Orchid", "Poppy", "Rose", "Sunflower", "Tulip"]
    @State private var isReady: Bool = false
    
    
    var body: some View {
        
        ScrollView(.vertical, showsIndicators: false){
            ZStack(alignment: .top){
                VStack(spacing: 40){
                    Text("Hello, world!")
//                    BarView(value: CGFloat(timeFromDatabase[0]), name: flowersName[0])
                    
                }
            }
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .top)
            
        }
        .navigationBarTitle(Text("Your datas in database").foregroundColor(.blue), displayMode: .inline)
        .onAppear{
            
            let gd = getDataFromDatabase()
            gd.readData { (quantity, time) in
                self.quantityFromDatabase = quantity!
                self.timeFromDatabase = time!       
            }
        }
    }
}

我不能使用值 self.quantityFromDatabase self.timeFromDatabase ,因为它们为空.我知道问题在于数据的异步检索.我已经尝试过 DispatchQueue.main.async ,但是我仍然没有得到这些值.如何获得它的另一种方法?我需要此值,因为我想在 VStack (此处的注释行)中绘制图表.

I cannot use values self.quantityFromDatabase and self.timeFromDatabase because are empty. I know the problem is with the asynchronous retrieval of data. I've tried with DispatchQueue.main.async, but I still not get these values. How is the other method to get it? I need this values, because I want to draw charts in VStack (the comment line there).

编辑

就像@Rexhin Hoxha在下面写的那样,我修改了代码,但是我不确定方法是否正确.我通过在类getDataFromDatabase中添加 @Published 来更改 var arrayWithQuantity = [Int]() var arrayWithTime = [Double]()GetDataFromDatabaseViewModel):

As @Rexhin Hoxha wrote below, i modified the code but i am not sure if the way is correct. I changed var arrayWithQuantity = [Int]() and var arrayWithTime = [Double]() by adding @Published in class getDataFromDatabase (now it's GetDataFromDatabaseViewModel):

class GetDataFromDatabaseViewModel : ObservableObject {

    @Published var arrayWithQuantity = [Int]()
    @Published var arrayWithTime = [Double]()
    
    func readData() {
       
        let db = Firestore.firestore()
        
        db.collection("amounts").getDocuments { (querySnapshot, err) in
            
            if let e = err{
                print("There's any errors: \(e)")
            }
            
            if err != nil{
                print((err?.localizedDescription)!)
                return
            }
            
            for i in querySnapshot!.documents{
                
                let quantityFromDb = i.get("amount") as! Int
                let timeFromDb = i.get("averageTimeRecognition") as! Double
                
                
                self.arrayWithQuantity.append(quantityFromDb)
                self.arrayWithTime.append(timeFromDb)
            }
            print("Array with quantity: \(self.arrayWithQuantity.count)")
        }
    }
}

也在结构中,我初始化了 @ObservedObject var gd = GetDataFromDatabaseViewModel() onAppear 现在看起来像这样:

also in struct I initialized @ObservedObject var gd = GetDataFromDatabaseViewModel() and onAppear now looks like this:

.onAppear{
            
            self.gd.readData()
            print("Quantity after reading: \(self.gd.arrayWithQuantity.count)")
        }

但是在onAppear中打印仍然会打印一个空数组.我在哪里弄错了?

but print in onAppear still print an empty Array. Where did I do a mistake?

推荐答案

所以问题出在您的完成处理程序中.它会在您检索数据之前返回.

So the problem is in your completion handler. It returns before you retrieve the data.

解决方案是使数组@Published并从视图中实时读取数据.您必须删除完成处理程序.

Solution is to make your arrays @Published and read the data in real time from the view. You have to remove the completion handler.

在"onAppear()"上调用该函数,然后使用@ObservedObject绑定到您的ViewModel(getDataFromDatabase).这就是在SwiftUI中完成的过程.

Call the function on ‚onAppear()‘ and use @ObservedObject to bind to your ViewModel (getDataFromDatabase). This is how it’s done in SwiftUI.

请大写首字母,并使用更通用的名称,例如"YouViewName" ViewModel.

Please capitalize the first letter and use something more generic like „YouViewName"ViewModel.

您的名字适合方法/函数,但不适用于类

Your name is fine for a method/function but not for a Class

这篇关于在onAppear中获取SwiftUI异步数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆