[英]Array is updating before variables are updated in Swift
I'm trying to get list of toys from Firestore and put it into array But when I call function, it returns empty array, and just after returning it prints Toy object, so order is broken.我正在尝试从 Firestore 获取玩具列表并将其放入数组但是当我调用 function 时,它返回空数组,并且在返回后立即打印玩具 object,因此顺序被破坏。
I thought that closures would help me, but I think I don't know how to use them, and examples from Google don't help me我认为闭包会对我有所帮助,但我认为我不知道如何使用它们,并且来自 Google 的示例对我没有帮助
Here is my code (I use SwiftUI so I created swift file with variable)这是我的代码(我使用 SwiftUI 所以我创建了带有变量的 swift 文件)
let db = Firestore.firestore()
class DataLoade {
func loadFirebase(completionHandler: @escaping (_ toys: [Toy]) -> ()){
var toysar: [Toy] = []
let toysRef = db.collection("Toys")
toysRef.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
var name: String = document.get("name") as! String
var id: Int = document.get("id") as! Int
var description: String = document.get("description") as! String
var imageName: String = document.get("imageName") as! String
var price: String = document.get("price") as! String
var category: String = document.get("category") as! String
var timeToy = Toy(id: id, name: name, imageName: imageName, category: category, description: description, price: price)
toysar.append(timeToy)
}
}
}
completionHandler(toysar)
// print(toysar)
}
}
that's what it prints out:这就是它打印出来的内容:
[] // it prints empty array, but it is in the end of the code
Toy(id: 1001, name: "Pikachu", imageName: "pikachu-plush", category: "lol", description: "kek", price: "350₽") // and now it prints Toy object, however it is in the start of the code
Ok, so I tried to make completion handler for my function, like in "duplicated" answer, but that doesn't work: array is returning before completion handler works好的,所以我尝试为我的 function 制作完成处理程序,就像在“重复”答案中一样,但这不起作用:数组在完成处理程序工作之前返回
ContentView.swift
func updateArray() -> [Toy]{
dl.loadFirebase() { toys in
ll = toys
}
print("lol \(datas)") // prints «lol []»
return ll
}
You can wait for an asynchronous task using a DispatchGroup
.您可以使用
DispatchGroup
等待异步任务。 But the trick is NOT to associate asynchronous tasks with return
statements.但诀窍是不要将异步任务与
return
语句相关联。 Instead, use closures
to do an action after the task is done.相反,在任务完成后使用
closures
来执行操作。 Disclaimer: I wrote this on SO, I apologize in advance for syntax issues.免责声明:我在 SO 上写了这个,我提前为语法问题道歉。
let toyData = loadFirebase( { (toys) in
print(toys)
//Do something with toys when done
//You could add another completionHandler incase it fails.
//So 1 for pass and 1 for fail and maybe another for cancel. W/e u want
} )
let db = Firestore.firestore()
func loadFirebase(completionHandler:@escaping ((toys: [Toy]?) -> Void)) {
//Create Group
let downloadGroup = DispatchGroup()
var toysar: [Toy] = []
let toysRef = db.collection("Toys")
//If you had multiple items and wanted to wait for each, just do an enter on each.
downloadGroup.enter()
toysRef.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
var name: String = document.get("name") as! String
var id: Int = document.get("id") as! Int
var description: String = document.get("description") as! String
var imageName: String = document.get("imageName") as! String
var price: String = document.get("price") as! String
var category: String = document.get("category") as! String
var timeToy = Toy(id: id, name: name, imageName: imageName, category: category, description: description, price: price)
toysar.append(timeToy)
print(timeToy)
}
//We aren't done until AFTER the for loop, i.e., each item is grabbed.
downloadGroup.leave()
}
}
//Once the queue is empty, we notify the queue we are done
downloadGroup.notify(queue: DispatchQueue.main) {
completionHandler(toys)
}
}
import SwiftUI
var dl = DataLoade()
var ll: [Toy] = []
let semaphore = DispatchSemaphore(value: 1)
struct ContentView: View {
var items: [Toy]
var body: some View {
NavigationView{
ScrollView(){
VStack(alignment: .leading){
ToyRow(category: "Наш выбор", toys: items)
Spacer()
ToyRow(category: "Акции", toys: items)
}
}.navigationBarTitle(Text("Игрушки г.Остров"))}
}
}
func upe(completionHandler:@escaping ((toys: [Toy]?){
dl.loadFirebase(completionHandler: { toy in
ll.append(contentsOf: toy!)
completionHandler(ll)
} )
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
upe(completionHandler: { (toys) in
DispatchQueue.main.async {
ContentView(items: toys)
}
})
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.