在onAppear中获取SwiftUI异步数据 [英] SwiftUI Async data fetch in onAppear
问题描述
我有一个类 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屋!