如何让类中的初始化方法等待 Firestore 在 Swift 4 中完成?

Posted

技术标签:

【中文标题】如何让类中的初始化方法等待 Firestore 在 Swift 4 中完成?【英文标题】:How to make initializer method in class wait for Firestore to finish in Swift 4? 【发布时间】:2019-03-03 02:51:01 【问题描述】:

我正在调用一个函数,该函数初始化一个类,并且在该类中我有一个初始化方法,该方法向 Firestore 发出请求。我在那个类中也有一个变量,一旦我完成了对数据库的循环,我将这个 self.variable 更改为等于我刚刚创建的任何内容。出于某种原因,我无法完成此操作,并且当我初始化我的类对象时,变量的值永远不会改变。

(假设 User 类只包含姓名和年龄)

这是我调用函数并初始化对象的地方

fileprivate func fetch()
    let homeObject = Home()
    print (homeObject.user.count)
    //count prints out as 0
    print (homeObject.test)
    //test prints out as 2 .. should be 3 but I'm not sure why?

这是 Home 的类

class Home
    var user: [User] = []
    var test = 1
    required init() 
        self.test = 2
        var userLoop = [User]()
        let db = Firestore.firestore()
        db.collection("users").getDocuments()  (querySnapshot, err) in
            if let err = err 
                print("Error getting documents: \(err)")
             else 
                for document in querySnapshot!.documents 

                    print("\(document.documentID) => \(document.data())")

                    let name_data = document.data()["name"]! as! String
                    let age_data = document.data()["age"]! as! String

                    let userTemp = User(name: name_data , age: age_data)

                    self.test = 3
                    userLoop.append(userTemp)
                
                self.user = userLoop

            
        
    

由于某种原因,test 能够更改为数字 2,但我相信这个初始化方法没有完成,因为它没有转到数字 3(如您在上面看到的,稍后在初始化函数中我将其更改为数字 3)。我非常感谢您的帮助,现在已经坚持了几个小时!

【问题讨论】:

“异步”是什么意思? 也许您可以将最终需要初始化的东西声明为可选变量。那么,在一个成功响应的完成块中,那么你可以初始化它吗? Firebase 是异步的;因此这一行 print (homeObject.user.count) 在 firebase 关闭之前执行,因为代码比互联网快。这个问题之前已经被问过很多次了。 this answer 应该增加一些清晰度。在[firebase]firebase is asynchronous 上搜索并阅读问答。 @Jay 我看到了这个解决方案,它与我的问题有点不同。是的,我可以在我的 Home 类中所需的 init 方法中做一些事情,但是我需要在创建 home 之后,就在此期间获取这些信息。此外,它仅在我将所需的 init 方法更改为函数方法并在我的 fetch 函数中调用它时才有效。 问题是你试图像函数一样调用firebase,但这是行不通的。需要做的是首先从 Firestore 获取数据,然后使用该数据初始化您的 Home var。所以调用 Firestore 来获取所需的文件,然后用它们初始化你的 var let home = HomeClass(initWithDocuments: documents) 【参考方案1】:

使用如下完成块初始化Home

class Home
    var user: [User] = []
    required init(with block: (Home)->Void) 
        var userLoop = [User]()
        let db = Firestore.firestore()
        db.collection("users").getDocuments()  (querySnapshot, err) in
            if let err = err 
                print("Error getting documents: \(err)")
             else 
                for document in querySnapshot!.documents 

                    print("\(document.documentID) => \(document.data())")

                    let name_data = document.data()["name"]! as! String
                    let age_data = document.data()["age"]! as! String

                    let userTemp = User(name: name_data , age: age_data)

                    userLoop.append(userTemp)
                
                self.user = userLoop

            
            block(self)
        
    

并将其称为:

var home = Home  (home) in
    //set your properties if needed.

【讨论】:

嗯,这并没有真正提供解决方案。虽然 home 中的 var 可以在 var home = Home 闭包中初始化,但之后的任何代码都将在 before home 被初始化之前执行。通过向类添加 var 来复制问题,在 var home = Home 中分配一个值,然后添加一个 print 语句以在闭包后打印 var。它在类闭包中的代码之前执行时打印一个空字符串,这仍然与问题中的问题相同。此外,block(self) 会抛出错误 关闭使用非转义参数 'block' 可能会允许它转义

以上是关于如何让类中的初始化方法等待 Firestore 在 Swift 4 中完成?的主要内容,如果未能解决你的问题,请参考以下文章

关于this的使用

Firestore,Flutter,Async:方法不等待异步方法完成

Firestore:引用类型。如何等待evey结果的所有get()调用

重载与重写

类概念

java小知识点2