简体   繁体   中英

How to convert document to a custom object in Swift 5?

I've been trying to convert the document retrieved from the Firebase's Cloud Firestore to a custom object in Swift 5. I'm following the documentation:

However, Xcode shows me the error Value of type 'NSObject' has no member 'data' for the line try $0.data(as: JStoreUser.self) . I've defined the struct as Codable .

The code:

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)
            }
        }
    }
}

The user struct:

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

The screenshot:

截图

Does anyone know how to resolve this?

After contacting the firebase team, I found the solution I was looking for. It turns out I have to do import FirebaseFirestoreSwift explicitly instead of just doing import Firebase . The error will disappear after this. (And of course you'll need to add the pod to your podfile first:D)

You can do it as shown below:-

First create model class:-

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
    }
}

Then you can convert firestore document into custom object as shown below:-

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)
    }
}

You need to initialize your struct and then you can extend the QueryDocumentSnapshot and QuerySnapshot like:

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
    }
}

Then, try to call the Firestore db by:

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
}

let jsonData = try JSONSerialization.data(withJSONObject: jsonObj, options: .prettyPrinted)

let jsonModel: Model = try JSONDecoder().decode(Model.self, from: jsonData)

In the past, I had some issues though importing FirebaseFirestore with the package manager in my project. So I explain about the access to FirebaseFirestore in swift.

  1. SnapshotListener

     import Foundation import FirebaseFirestore class BooksViewModel: ObservableObject { @Published var books = [Book]() private var db = Firestore.firestore() func fetchData() { db.collection("books").addSnapshotListener { (querySnapshot, error) in guard let documents = querySnapshot?.documents else { print("No documents") return } self.books = documents.map { queryDocumentSnapshot -> Book in let data = queryDocumentSnapshot.data() let title = data["title"] as? String?? "" let author = data["author"] as? String?? "" let numberOfPages = data["pages"] as? Int?? 0 return Book(id:.init(), title: title, author: author, numberOfPages: numberOfPages) } } } }
  2. using uid and getDocument function

     Firestore.firestore().collection("users").document(uid).getDocument { snapshot, error in if let error = error { self.errorMessage = "Failed to fetch current user: \(error)" print("Failed to fetch current user:", error) return } guard let data = snapshot?.data() else { self.errorMessage = "No data found" return } let uid = data["uid"] as? String?? "" let email = data["email"] as? String?? "" let profileImageUrl = data["profileImageUrl"] as? String?? "" self.chatUser = ChatUser(uid: uid, email: email, profileImageUrl: profileImageUrl) }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM