【问题标题】:Why is Firestore's getDocument method returning an empty dictionary?为什么 Firestore 的 getDocument 方法返回一个空字典?
【发布时间】:2020-10-05 02:22:21
【问题描述】:

我正在用 Swift 制作一个 iOS 应用程序,用户数据存储在 Firebase Firestore 数据库中。 Firestore 中的用户文档由用户的 UID 命名。要从 Firestore 获取数据,我有 getUserData 函数:

static func getUserData(uid: String) -> [String : Any] {
        
        let userRef = Firestore.firestore().collection(Constants.Firestore.Collections.users)
        let userDocRef = userRef.document(uid)
        
        var temp: [String : Any] = [:]
        
        userDocRef.getDocument { (document, error) in
            guard let document = document, document.exists else {
                print("document does not exist")
                return
            }
                
            let dataDesc = document.data()
            
                
            temp = dataDesc!

        }
    
        return temp
        
    }

我在我的用户类的初始化程序中调用此方法:

class User {
    // MARK: - Properties
    var firstName: String
    var lastName: String
    let uid: String
    let phone: String
    var available: Bool
    var friends: [User] = []

    init?(firestoreUID: String) {
                
        self.uid = firestoreUID
        
        let data = UserService.getUserData(uid: firestoreUID)
        print(data.keys)
        
        guard let phone = data[Constants.Firestore.Keys.phone] as? String,
            let available = data[Constants.Firestore.Keys.available] as? Bool,
            let firstName = data[Constants.Firestore.Keys.firstName] as? String,
            let lastName = data[Constants.Firestore.Keys.lastName] as? String
            else {
                return nil
        }
        
        self.phone = phone
        self.available = available
        self.firstName = firstName
        self.lastName = lastName
    }
}

但是,当我打开用户实例时,它会给出一个 nil 值。当我从 getUserData 函数打印检索到的字典的键时,控制台只显示一个空数组。我做错了什么,我该如何解决这个问题,以便我真正从 Firestore 获取我的用户数据?

编辑:我已将 getUserData 更改为老板的答案,但我不确定我的 User 类初始化中应该包含什么。我尝试了 ``` 建议的调用格式 UserService.getUserData(uid: firestoreUID) { (data) in

        if let data = data {
            print(data.keys)
            temp = data
            
        } else {
            print("User not found")
            return
        }
        
    }

但当我尝试查询临时字典时,仍然收到“致命错误:打开可选值时意外发现 nil”。

【问题讨论】:

  • 不要将此异步方法放在对象的初始化程序中。先获取数据,再用它初始化对象。
  • 进行了更改,但仍然 nil 被解包,所以我检查并意识到我在 getUserData 调用的完成块中的代码永远不会被执行。从我在网上发现的情况来看,这个问题通常是通过在函数定义中不调用 completion() 来调用的,我肯定在这样做。有什么建议吗?
  • 这能回答你的问题吗? Returning data from async call in Swift function
  • @bsod 的答案非常好,但它可能不是这个用例的最佳解决方案,它使用的是完成处理程序,这似乎不是你想要的。我似乎正在尝试从 Firebase 读取数据并填充用户对象 - 问题是,接下来会发生什么?例如这是否是用户登录的应用程序身份验证功能的一部分,您从 Firebase 读取他们的数据,然后可能会向他们展示任务列表或其他视图?填充用户对象后,下一步会发生什么?
  • 下一步是访问用户对象的属性以显示自定义 UILabel。我想我得到了 bsod 为标签工作的答案,但我的应用程序的一部分包括一个朋友列表,并且使用 async getData 获取完整列表对我来说有点困难,尽管我对此很陌生。

标签: swift firebase google-cloud-firestore


【解决方案1】:

userDocRef.getDocument 是异步的,这意味着获取文档的调用之后紧跟代码return temp 中的下一行。它不会等待数据库获取文档,因此您将始终返回nil;这就是异步的工作原理(相对于同步)。

在 Swift 中,你不能(或者绝对不应该)创建一个异步返回的函数。相反,该函数应该有一个转义完成处理程序,该处理程序将异步对象作为其参数之一返回。

static func getUserData(uid: String, _ completion: @escaping (_ data: [String: Any]?) -> Void ) {
    let userRef = Firestore.firestore().collection(Constants.Firestore.Collections.users)
    let userDocRef = userRef.document(uid)

    userDocRef.getDocument { (document, error) in
        guard let document = document, document.exists else {
            print("document does not exist")
            completion(nil)
            return
        }
        completion(document.data())
    }
}

用法

getUserData(uid: userId) { (data) in
    if let data = data {
        ...
    } else {
        ...
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-25
    • 1970-01-01
    • 2020-11-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多