简体   繁体   English

在 Swift 中更新变量之前,数组正在更新

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM