首页 > 解决方案 > 当每次都没有进入for循环时,如何等到在Swift中执行查询?

问题描述

我想检查我的任何用户在创建新帐户期间是否使用与我的新用户相同的用户名。如您所见,我正在使用查询从 firebase 获取文档,但 usernameTaken() 比执行查询更快地返回输出。我正在尝试使用 DispatchGroup(第一次),但我无法获得我想要的结果。基本上,一旦进入 for 循环,我想更改变量 isTaken 的值。这是我的 usernameTaken() 函数,带有 Firebase 查询和 DispatchGroup 尝试:

func usernameTaken() -> Bool {
    let currentUsername = usernameTextField.text
    var isTaken = false
    let group = DispatchGroup()
    
    db.collection((K.FStore.usersCollection)).whereField(K.FStore.usernameField, isEqualTo: currentUsername!)
    .getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
            } else {
                for document in querySnapshot!.documents {
                    group.enter()
                    print("Same username ID: \(document.documentID)")
                    print("Username used")
                    isTaken = true
                    group.leave()
                }
            }
    }
    group.notify(queue: .main) {
        print(isTaken)
        print("Group notify")
    }
    print("82 : \(isTaken)")
    return isTaken
}

当我尝试使用已使用的用户名注册时,这是我的控制台。在此处输入图像描述

据我所知,当不使用用户名时,不会输入 for 循环。我在这里做错了什么?也许有更好的方法来检查用户名是否已在 Firebase 中使用?感谢您的时间和帮助!

标签: iosswiftfirebasegoogle-cloud-firestore

解决方案


您的函数(对 Firestore 进行网络调用)不能是同步的——这意味着它会在函数有效完成后立即返回(在本例中为布尔值)。那是因为 Firestore 需要一些时间来查询数据库并返回您的文档。因此,您的函数本质上应该是异步的,这意味着它可以在控制退出函数后“返回”事物。而在 Swift 中,最好的方法是通过完成处理程序。

func usernameTaken(_ completion: @escaping (_ taken: Bool?) -> Void) {
    let currentUsername = usernameTextField.text
    
    db.collection((K.FStore.usersCollection)).whereField(K.FStore.usernameField, isEqualTo: currentUsername!).getDocuments() { (querySnapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
            completion(nil) // error; unknown if taken
        } else {
            if querySnapshot!.isEmpty {
                completion(false) // no documents; not taken
            } else {
                completion(true) // at least 1 document; taken
            }
        }
    }
}

usernameTaken { (taken) in
    guard let taken = taken else {
        return // value is nil; there was an error—consider retrying
    }
    if taken {
        print("username is taken")
    } else {
        print("username is available")
    }
}

我还将返回值设为可选布尔值,以便调用者可以判断是否有错误(当值为 时nil)。


推荐阅读