swift Firestore异步问题

xv8emn3q  于 2023-02-11  发布在  Swift
关注(0)|答案(2)|浏览(119)

我正在调用一个Firestore查询,它确实会返回,但我需要确保在继续执行其余代码之前完成,所以我需要一个完成处理程序......但对于我的生活来说,我似乎无法编写它。

// get user info from db
    func getUser() async {
        self.db.collection("userSetting").getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
            } else {
                for document in querySnapshot!.documents {
                    let userTrust = document.data()["userTrust"] as! String
                    let userGrade = document.data()["userGrade"] as! String
                    let userDisclaimer = document.data()["userDisclaimer"] as! String
                    
                    var row = [String]()
                    row.append(userTrust)
                    row.append(userGrade)
                    row.append(userDisclaimer)
                    
                    self.userArray.append(row)
                    
                    // set google firebase analytics user info
                    self.userTrustInfo = userTrust
                    self.userGradeInfo = userGrade

                }
            }
            
        }
    }

电话:

internal func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        FirebaseApp.configure()
        db = Firestore.firestore()
        Database.database().isPersistenceEnabled = true

        Task {
            do {
                let userInfo = await getUser()
            }
        } return true }

我使用了一个任务,因为didFinishLauncingWithOptions是同步的,而不是异步的
但是,在didFinishLauncingWithOptions继续之前,getUser()仍然没有完成。
我需要getUser的数据,因为下一个步骤使用数组中的数据,如果没有它,我会得到一个“越界异常”,因为数组仍然是空的。
还尝试在func getUser()中使用调度组。同样没有效果。
最后尝试完成处理程序:

func getUser(completion: @escaping (Bool) -> Void) {

        self.db.collection("userSetting").getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
            } else {

                for document in querySnapshot!.documents {

                    let userTrust = document.data()["userTrust"] as! String
                    let userGrade = document.data()["userGrade"] as! String
                    let userDisclaimer = document.data()["userDisclaimer"] as! String
                    
                    var row = [String]()
                    row.append(userTrust)
                    row.append(userGrade)
                    row.append(userDisclaimer)
                    
                    self.userArray.append(row)
                    
                    // set google firebase analytics user info
                    self.userTrustInfo = userTrust
                    self.userGradeInfo = userGrade
                    
                    completion(true)
                    }
                
                }
            }
        
        }

没有任何效果。getUser调用在代码继续运行之前没有完成。有人能帮帮我吗?我已经搜索了很多次,查看了所有链接的答案,但我不能使这个工作。我显然错过了一些简单的东西,请帮帮我

owfi6suc

owfi6suc1#

阅读此帖子:Waiting for data to be loaded on app startup.
它解释了为什么在从函数application(_:didFinishLaunchingWithOptions)返回之前不应该等待数据。
要实现您的需要,您可以将第一个ViewController用作一种闪屏(只显示图像或活动指示器),并在viewDidLoad()方法中调用函数getUser(completion:) ViewController。
示例:

class FirstViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        MyFirestoreDatabaseManager.shared.getUser() { success in
            if success {
                //TODO: Navigate to another ViewController
            } else {
                //TODO: Show an error
            }
        }
    }
}

其中MyFirestoreDatabaseManager.shared显然是在其上定义getUser(completion:)方法的对象。
(In在你的例子中,我认为你在AppDelegate中定义了那个函数。在这种情况下,你应该把你的getUser(completion:)方法和所有相关变量标记为static。然后用AppDelegate替换MyFirestoreDatabaseManager.shared)。

slmsl1lt

slmsl1lt2#

我不能100%确定你想要完成什么,因为我看不到你所有的代码,但是尝试类似的东西,替换你试图从文档返回的对象。
你不希望你的用户数据分散在多个文档中。使用Firebase,你需要为你必须获得的每个文档付费。理想情况下,你希望你的所有用户设置都在一个Firebase文档中。然后创建一个UserInfo结构体,你可以使用库CodeableFirebase或你选择的解码器解码到该结构体。

// Create user struct
struct UserInfo: Codable {
    var userId: String
    var userTrust: String
    var userGrade: String
    var userDisclaimer: String
}

// get user info from db and decode using CodableFirebase
func getUser() async throws -> UserInfo {
    let doc = try await self.db.collection("users").document("userIdHere")
    let userInfo = try FirestoreDecoder().decode(UserInfo.self, from: doc.data())
    return UserInfo
}

你就能做到...

Task {
    do {
        let userInfo = try await getUser()
        let userTrust = userInfo.userTrust
        let userGrade = userInfo.userGrade
        let userDisclaimer = userInfo.userDisclaimer
    }
}

相关问题