【问题标题】:Is Firebase getDocument run line by line?Firebase getDocument 是否逐行运行?
【发布时间】:2020-05-02 15:30:50
【问题描述】:

我是一名 swift 和 Firebase 初学者,我遇到了一个让我很困惑的问题。我们都知道下面的代码

var a = [Int]()
for i in 0..2{
    a.append(i)
    print(a)
print(a)

应该给我输出

[0]
[0,1]
[0,1,2]
[0,1,2]

结果是真的。但是,当我处理 getDocument() 并编写类似的逻辑代码时,输​​出很奇怪!代码如下。

override func viewDidLoad() {
    super.viewDidLoad()
    let docSecond = getThirtyData()
    getDataContent(thirtyData: docSecond)
}
func getThirtyData()->Array<Int>{
    var querySecond = [Int]()
    var docSecond = [Int]()
    let postDoc = db.collection("announcement")
    postDoc.getDocuments { (querySnapshot, err) in
        if let err = err{
            print("Error getting documents: \(err)")
        }else{
            for document in querySnapshot!.documents{
                //print(document.data()["postTimeSecondInt"] as! Int)
                querySecond.append(document.data()["postTimeSecondInt"] as! Int)
            }
            for _ in 1...querySecond.count{
                let max = querySecond.max()!
                docSecond.append(max)
                let index = querySecond.firstIndex(of: max)
                querySecond.remove(at: index!)
            }
            print(docSecond)
            print("123")
        }
    }
    print(docSecond)
    print("456")
    return docSecond
}

func getDataContent(thirtyData: [Int]){
    print(thirtyData)
    print("789")
}

我认为结果可能与首先打印“123”,然后是“456”,然后是“789”的逻辑相同。但是,结果如下所示。

[]
456
[]
789
[1588428987, 1588428980, 1588427392]
123

似乎它与 for 循环同时运行下面的代码行。谁能解释为什么会这样?

【问题讨论】:

    标签: ios swift firebase google-cloud-firestore


    【解决方案1】:

    这是按预期/记录在案的,但如果您从未使用过异步 API,它确实会令人困惑。代码执行乱序的原因是postDoc.getDocuments() 必须从服务器读取数据,这可能需要一些时间。允许您的主代码继续运行,而不是阻止您的代码(从而阻止用户使用您的应用程序)。然后当数据从服务器可用时,您的完成处理程序会使用该数据调用。

    通过添加一些日志语句最容易看到这一点:

    print("Before starting to load data")
    let postDoc = db.collection("announcement")
    postDoc.getDocuments { (querySnapshot, err) in
        print("Got data");
    }
    print("After starting to load data")
    

    当你运行这个最小的代码时,它会打印:

    开始加载数据之前

    开始加载数据后

    得到数据

    这是按预期工作的,但如果您从未使用过异步或事件驱动的 API,这确实会让人感到困惑。不幸的是,大多数现代云/Web API 都是异步的,所以最好习惯这种模式。希望我上面的解释对此有所帮助。

    要记住两件重要的事情:

    • 你的print(docSecond) 没有打印你想要的数据,因为docSecond.append(max) 还没有运行。
    • 任何需要来自数据库的数据的代码都需要位于使用该数据调用(或从那里调用)的完成处理程序中。

    您不能返回异步加载的数据。典型的解决方法是创建一个自定义完成处理程序,与 Firestore 的 getDocuments() 接受 postDoc.getDocuments { (querySnapshot, err) in 的完成处理程序非常相似,但随后使用您自己的类型。

    类似:

    func getThirtyData(_ completion: (Array<Int>) -> ()) {
        var querySecond = [Int]()
        var docSecond = [Int]()
        let postDoc = db.collection("announcement")
        postDoc.getDocuments { (querySnapshot, err) in
            if let err = err{
                print("Error getting documents: \(err)")
            }else{
                for document in querySnapshot!.documents{
                    querySecond.append(document.data()["postTimeSecondInt"] as! Int)
                }
                for _ in 1...querySecond.count{
                    let max = querySecond.max()!
                    docSecond.append(max)
                    let index = querySecond.firstIndex(of: max)
                    querySecond.remove(at: index!)
                }
                completion(docSecond)
            }
        }
    }
    

    然后这样称呼它:

    getThirtyData { docSecond in
       getDataContent(thirtyData: docSecond)
    }
    

    另见:

    【讨论】:

    • 非常感谢,对我帮助很大!我是软件工程师的新手,异步的概念对我来说是新的。谢谢你给我上了一课!
    • 不客气。对于许多刚接触异步 API 的开发人员来说,这是主要的绊脚石之一,所以如果你一直爱上它,请不要放弃。我花了几年的时间才让这些 API 成为第二天性。
    猜你喜欢
    • 1970-01-01
    • 2020-07-29
    • 1970-01-01
    • 2018-01-08
    • 1970-01-01
    • 1970-01-01
    • 2018-08-25
    • 2019-12-16
    • 2015-12-31
    相关资源
    最近更新 更多