将数据从 Firestore 映射到 Swift 中的结构 - IOS

Posted

技术标签:

【中文标题】将数据从 Firestore 映射到 Swift 中的结构 - IOS【英文标题】:Map Data From Firestore to a struct In Swift - IOS 【发布时间】:2019-06-07 09:43:29 【问题描述】:

我正在尝试将从我的 Firestore 数据库中检索到的“用户”映射到我在代码中定义的用户结构,但我认为我没有正确理解 swift 中的映射功能。

如何将检索到的用户映射到结构中?

结构

struct User 
// Properties

    var firstName: String
    var lastName: String
    var userName: String
    var email: String

    init(firstName: String, lastName: String, userName: String, email: String) 
        self.firstName = firstName
        self.lastName = lastName
        self.userName = userName
        self.email = email
    

从 Firestore 获取用户的函数

func getUser(UID: String) 
    // Firebase setup
    settings.areTimestampsInSnapshotsEnabled = true
    db.settings = settings

    db.collection("users").document(UID).getDocument  (document, error) in
        if let error = error 
            print("Error: \(error.localizedDescription)")
         else 
            print(document!.data()!)
        
    

【问题讨论】:

不相关,但您在 User 结构中提供的 init 是不必要的。您将自动获得相同的init,而无需自己编写。 哦,谢谢你的提示!我没有意识到它是自动的。您是否碰巧知道如何通过@rmaddy 进行这种映射? ***.com/questions/43786471/… 这个呢? 该解决方案绝对有效!但是有没有办法使用 swift 中的映射功能来做到这一点?我计划构建的一些数据库模型会更大更复杂。我也只是想学习如何使用这些功能以供将来参考@emrepun 你可能想让你的结构符合Codable 协议(Encodable & Decodable)。如果您的结构只是字符串,则您无需实现任何东西,只需符合该​​协议即可完成,否则,如果您的 User 结构中有子对象,您将不得不编写自己的解析。有了这个,您可以使用快照中的字典来构建User 【参考方案1】:

查询的 Firestore 文档的类型为 [String: Any],因此请配置您的初始化程序以接受该类型的字典。因为您正在处理数据库返回,所以永远不能保证数据会完全完整,所以我建议让您的初始化程序失败,这意味着它可以返回 nil(它可能会失败)。

我以您的为例,将email 属性设为可选。在下面的示例中,实例化User 对象只需要四个属性中的三个。

let info: [String: Any] = ["hasFriends": true]
let firestoreData: [String: Any] = ["firstName": "lance", "lastName": "stevenson", "userName": "lstevenson", "info": info]

struct User 
    var firstName: String
    var lastName: String
    var userName: String
    var info: [String: Any]
    var email: String?
    var hasFriends: Bool
    
    init?(data: [String: Any]) 
        guard let firstName = data["firstName"] as? String,
            let lastName = data["lastName"] as? String,
            let userName = data["userName"] as? String,
            let info = data["info"] as? [String: Any],
            let hasFriends = info["hasFriends"] as? Bool else 
                return nil
        
        self.firstName = firstName
        self.lastName = lastName
        self.userName = userName
        self.info = info
        self.hasFriends = hasFriends
        self.email = data["email"] as? String // User will be created even if this is nil
    


if let user = User(data: firestoreData) 
    print(user.hasFriends) // true

我不建议您为此使用 Swift 的映射工具,因为您可能会在同一个字典中为不同的模型处理不同类型的值。并且在初始化程序中用这些变量映射这个字典的代码并不漂亮。

【讨论】:

这个解决方案效果很好,我从来没有想过!但是,假设在我的 firebase 数据库中,我有一个“信息”属性,它本身就是一个不同类型的字典。例如,它有一个字典,其中包含用户的好友列表,以及布尔值等不同的属性。如何在 swift 中访问从这个嵌套属性返回的特定属性? 我更新了我的答案。将其复制并粘贴到 Playground 中,然后随意玩弄,直到您感到舒服为止。 这非常有效!正如您可能知道的那样,我是编码新手,因此将每个属性设为可选是标准做法吗,因为理论上数据库调用可能会像您所说的那样返回部分数据? 这是需要考虑的一件事。要考虑的另一件事是,如果您将它们全部设为可选并且它们全部/大部分为零,您真的会使用该用户对象吗?您的 UI 是否会更好地丢弃该用户并获得下一个用户?我们也在与谷歌打交道;可靠性并没有变得更高。但最终决定权在你,作为工程师。什么对你最有意义?就个人而言,我会假设 Firebase 和网络将在 99.x% 的时间内交付,因此我不会将它们全部设为可选,但我会保持初始化程序作为一般安全网失效。 我觉得使用 nil 合并运算符会更合适,而不是在缺少某些值时使整个用户失败。例如:self.firstName = firstName ?? "ERR"

以上是关于将数据从 Firestore 映射到 Swift 中的结构 - IOS的主要内容,如果未能解决你的问题,请参考以下文章

从 Firestore 获取数据并将其映射到提供程序对象

如何将 ViewModel 的 ID 映射到 Firestore 中的文档 ID?

如何将一组地图从 Firestore 映射到 recyclerView?

使用 Stream 从 FireStore 获取数据并将其映射到 Flutter 类

将 Firebase 身份验证用户映射到 Firestore 文档

使用 Swift 将数据上传到 Firestore 时出错