如何在 Swift 5 中将文档转换为自定义对象?

Posted

技术标签:

【中文标题】如何在 Swift 5 中将文档转换为自定义对象?【英文标题】:How to convert document to a custom object in Swift 5? 【发布时间】:2020-04-20 06:16:25 【问题描述】:

我一直在尝试将从 Firebase 的 Cloud Firestore 检索到的文档转换为 Swift 5 中的自定义对象。我正在关注文档:

https://firebase.google.com/docs/firestore/query-data/get-data#custom_objects

但是,Xcode 向我显示了 Value of type 'NSObject' has no member 'data' 行的错误 try $0.data(as: JStoreUser.self)。我将结构定义为Codable

代码:

func getJStoreUserFromDB() 
    db = Firestore.firestore()
    let user = Auth.auth().currentUser
    db.collection("users").document((user?.email)!).getDocument()  
        (document, error) in
        let result = Result 
            try document.flatMap 
                try $0.data(as: JStoreUser.self)
            
        
    

用户结构:

public struct JStoreUser: Codable 
    let fullName: String
    let whatsApp: Bool
    let phoneNumber: String
    let email: String
    let creationDate: Date?

截图:

有谁知道如何解决这个问题?

【问题讨论】:

只需使用 Firestore 返回的字典初始化自定义对象 我不确定你在 .getDocument() 完成处理程序中做了什么,但我认为你需要将通过 guard let json = let json = try JSONSerialization.jsonObject(with: document.data(), options: []) as? [String:[String:Any]] 返回的 Data 转换为字典,或者类似的东西(您的数据的结构可能不是[String:[String:Any]])。从那里,您可以获取各个值并从这些值中初始化一个对象。正如 bsod 所提到的,您还可以在初始化程序中传递一个字典并以这种方式初始化一个对象。 等等,我正在查看您正在复制文档的哪一部分。我使用实时数据库,将请求返回的Data 通过JSONSerialization.jsonObject 转换为字典没有问题。只要请求返回的是 JSON 数据,你应该可以通过这个方法将它转换成一个对象。 这将有助于理解您在这里尝试做什么 - 您正在阅读的 Firestore 结构是什么样的以及 JStoreUser 类是什么?您是否正在尝试从 Firestore 文档中获取数据并从中制作 Swift 结构?注意这个 $0.data 是一个字典 【参考方案1】:

你可以这样做:-

首先创建模型类:-

import FirebaseFirestore
import Firebase

//#Mark:- Users model
struct CommentResponseModel 

    var createdAt : Date?
    var commentDescription : String?
    var documentId : String?

    var dictionary : [String:Any] 
        return [
                "createdAt": createdAt  ?? "",
                "commentDescription": commentDescription  ?? ""
        ]
    

   init(snapshot: QueryDocumentSnapshot) 
        documentId = snapshot.documentID
        var snapshotValue = snapshot.data()
        createdAt = snapshotValue["createdAt"] as? Date
        commentDescription = snapshotValue["commentDescription"] as? String
    

然后您可以将firestore文档转换为自定义对象,如下所示:-

func getJStoreUserFromDB() 
    db = Firestore.firestore()
    let user = Auth.auth().currentUser
    db.collection("users").document((user?.email)!).getDocument()  (document, error) in
        //        Convert firestore document your custom object
        let commentItem = CommentResponseModel(snapshot: document)
    

【讨论】:

感谢您的建议。但是,我正在寻找一种使用Codable 协议并将文档直接转换为对象的方法(如在Java 中,可以使用document.toObject(User.class)。)Firebase 文档显示了类似的内容,但由于某种原因它不起作用.【参考方案2】:

在联系 firebase 团队后,我找到了我正在寻找的解决方案。事实证明我必须明确地做import FirebaseFirestoreSwift 而不是仅仅做import Firebase。此后错误将消失。 (当然,您需要先将 pod 添加到您的 podfile 中:D)

【讨论】:

有效吗?因为我没有在导入自动完成中得到FirebaseFirestoreSwift 是的,您需要先添加pod FirebaseFirestoreSwift。然后你可以导入:D 你能分享我上面提到的 Pod 的 GitHub 存储库吗 firebase.google.com/docs/firestore/… 很高兴我能帮上忙:D【参考方案3】:

您需要初始化您的结构,然后您可以像这样扩展 QueryDocumentSnapshot 和 QuerySnapshot:

extension QueryDocumentSnapshot 
    func toObject<T: Decodable>() throws -> T 
        let jsonData = try JSONSerialization.data(withJSONObject: data(), options: [])
        let object = try JSONDecoder().decode(T.self, from: jsonData)
        
        return object
    


extension QuerySnapshot 
    
    func toObject<T: Decodable>() throws -> [T] 
        let objects: [T] = try documents.map( try $0.toObject() )
        return objects
    

然后,尝试通过以下方式调用 Firestore 数据库:

db.collection("users").document((user?.email)!).getDocument()  (document, error) in
    guard error == nil else  return 
    guard let commentItem: [CommentResponseModel] = try? document.toObject() else  return 
     // then continue with your code

【讨论】:

以上是关于如何在 Swift 5 中将文档转换为自定义对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何在喷雾中将所有拒绝转换为自定义 json?

如何在 Swift 中将内容包装为自定义视图

我们可以在 javascript 中将通用对象转换为自定义对象类型吗?

将 DataSnapshot 转换为自定义结构对象 - Swift 4

如何在 Python 中将日期时间对象转换为自纪元(unix 时间)以来的毫秒数?

如何在 Swift 5 中将“日期”转换为“数据”,反之亦然? [复制]