我正在尝试从Firestore获取玩具清单并将其放入数组中 但是,当我调用函数时,它返回空数组,并且在返回后立即打印Toy对象,因此顺序被破坏了。
我认为闭包可以帮助我,但我认为我不知道如何使用它们,而Google的示例也无济于事
这是我的代码(我使用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)
}
}
这就是打印出来的内容:
[] // 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
好吧,所以我试图为我的函数创建完成处理程序,就像在“重复的”答案中一样,但这是行不通的:在完成处理程序起作用之前,数组正在返回
ContentView.swift
func updateArray() -> [Toy]{
dl.loadFirebase() { toys in
ll = toys
}
print("lol \(datas)") // prints «lol []»
return ll
}
答案 0 :(得分:0)
您可以使用DispatchGroup
等待异步任务。但是诀窍不在于将异步任务与return
语句相关联。而是在完成任务后使用closures
来执行操作。
免责声明:我在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)
}
})
}
}