Home > OS >  How to turn manual mapping to automatic mapping when fetching data
How to turn manual mapping to automatic mapping when fetching data

Time:08-02

I have a function that fetches a user from FireStore. At the moment the function manually deals with the data. I want to change this using Codable. I have tried many functions but I cannot seem to get it to work. I think the code that is required is quite simple and short & I'm just not understanding something.

Here is the fetchUser function that needs to change to one that doesn't manually map the data:

let ref = Firestore.firestore()

func fetchUser(uid: String,completion: @escaping (UserModel) -> ()){

    let db = Firestore.firestore()
    @EnvironmentObject var sharedData: SharedDataModel

    ref.collection("Users").document(uid).getDocument { (doc, err) in
        guard let user = doc else{return}

        let username = user.data()?["username"] as? String ?? "No Username"
        let pic = user.data()?["imageurl"] as? String ?? "No image URL"
        let bio = user.data()?["bio"] as? String ?? "No bio"
        let uid = user.data()?["uid"] as? String ?? ""
        let isVerified = user.data()?["isVerified"] as? Bool ?? false

        DispatchQueue.main.async {
            completion(UserModel(username: username, pic: pic, bio: bio, uid: uid, isVerified: isVerified))
        }
    }
}

How do I change this function to manually map the data using Codable?

CodePudding user response:

try this approach, is this what you have tried already? Since I do not have your database, I cannot test this.

let ref = Firestore.firestore()

func fetchUser(uid: String, completion: @escaping (UserModel) -> ()){
    let db = Firestore.firestore()
    
    let docRef = db.collection("Users").document(uid).getDocument(as: UserModel.self) { result in

        switch result {
        case .success(let user):
            // A `UserModel` value was successfully initialized from the DocumentSnapshot.
            print("UserModel: \(user)")
            DispatchQueue.main.async {
                completion(user)
            }
            
        case .failure(let error):
            // A `UserModel` value could not be initialized from the DocumentSnapshot.
            print("Error decoding UserModel: \(error)")
            // handle errors todo
        }
    }
}

CodePudding user response:

Add extinsion

extension DocumentSnapshot {
    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
    }
}

confirm to decodable

struct UserModel:Decodable {
}

fetch user

func fetchUser(uid: String,completion: @escaping (UserModel?) -> ()){
        let ref = Firestore.firestore()
        ref.collection("Users").document(uid).getDocument() { (doc, err) in
            guard err == nil else { completion(nil)
                return
            }
            guard let model: UserModel = try? doc!.toObject() else {
                completion(nil)
                return
            }
            completion(model)
        }
    }

Second Way

user init with constructor as dict

struct UserModel {
    
    let uid:String
    let username:String
    let pic:String
    let bio:String
    let isVerified:Bool
    
    init?(value:[String:Any]) {
        guard let id = value["uid"] as? String else {
            return nil
        }
        uid = id
        username = value["username"] as? String ?? "No Username"
        pic = value["imageurl"] as? String ?? "No image URL"
        bio = value["bio"] as? String ?? "No bio"
        isVerified = value["isVerified"] as? Bool ?? false
    }
}

and fetch

func fetchUser(uid: String,completion: @escaping (UserModel) -> ()){

        let db = Firestore.firestore()
        db.collection("Users").document(uid).getDocument { (doc, err) in
            guard let documentSnap = doc,err == nil else {return}
            if let value = documentSnap.data() ,
               let user = UserModel(value: value) {
                completion(user)
            }
        }
    }
  • Related