mercredi 22 février 2023

IOS - Swift : Fetch the property name of an object using KeyPath

Issue :

Update the property of a specific object in Firebase. To do so I want to update one value only within an object without having to interact with the current object. The required part from firebase, other than the collection and the document are the key and the new value

I have figured an implementation which works - And I'd like some improvement ideas. Especially there, static func createEmpty() -> Self, this bothers me. Initializing a model to find a key seems really not efficient to me. I'd like if a nice swifty soul could show me the way.

Here how it looks:

This protocol will be the key property reader :

protocol KeyPathValueReadable {
    static func createEmpty() -> Self
}

extension KeyPathValueReadable {
   fileprivate subscript<T:Any>(at path : KeyPath<Self,T> ) -> String{
       print(self[keyPath: path])
       return "\(self[keyPath: path])"
   }
   func readValue<T : Any & Hashable>(at keyPath : KeyPath<Self,T>) -> String{
       let mirror = Mirror(reflecting: self)
       var dict : [T: String] = [:]
       for case let (label, value) in mirror.children {
           if let label = label {
               dict[value as! T] = label
           }
       }
       return dict[self[keyPath: keyPath]] ?? "no key at path"
   }
}

Here's an example of the model to update :

struct UserModel : Codable, KeyPathValueReadable {
    
    var name : String
    
     static func createEmpty() -> Self {
         return Self.init(name: "")
    }
}

And here is the client implementation and use :

protocol UpdateDataClientDelegate {
    associatedtype D : Codable & KeyPathValueReadable
}

extension UpdateDataClientDelegate {
    func update<T : Hashable>(in collection : String, for document : String, at path : KeyPath<D,T>, newValue : Any) {
        let key =  D.createEmpty().readValue(at: path)
        print(key)
        //update key with newValue
    }
}

struct UpdateUserClient : UpdateDataClientDelegate {
    typealias D = UserModel
}

let client = UpdateUserClient()

client.update(in: "pouf", for: "plaf", at: \.name, newValue: "chocolate")

Aucun commentaire:

Enregistrer un commentaire