dbenitobaldeon
dbenitobaldeon

Reputation: 324

what is the best way to save json data in swift model

I previously made a post about how to save json data in a model here . Good now I am developing a project on iOS with swift, and I face the following problem, it happens that sometimes the database administrators change the names of the columns constantly, I only consume services with the help of Alamofire, to save data in models, use camal case and snake case, At the moment everything is fine but I would like to know what is the best way to save json data in a swift model, in my experience with Android I used retrofit with @Serializename and it worked great because if the json attribute of the service it was modified I only had to update a line of code and my variable could be kept the same, this helped me maintain a better order and it made it scalable.

In some cases the json comes to me.

{
 "price": "385.000000",
 "nameusser": null,
 "favorite": 43,
 "short_nameProduct": "Génifique Repair Sc",
 "description_product": "Génifique repair sc es la crema de noche antiedad de lancôme. Despiértese con una piel fresca y rejuvenecida con nuestra crema de noche.",
 "alt": null,
 "photo": "https://url/020021000112-1.png"
}

in swift it would generate my model in the following way.

struct Product : Codable {
    let price : String?
    let nameusser : String?
    let favorite : Int
    let shortNameProduct : [Product]
    let description : [Galery]
    let alt : Product
    let success : Bool
}

The problem here is that my variables must fit the json I get to use the JSONDecoder() and the convertFromSnakeCase, I can not define them myself.

while in java android I just have to do it like that.

@SerializedName("price")
private String price;
@SerializedName("nameusser")
private String name;
@SerializedName("favorite")
private Int favorite;
@SerializedName("short_nameProduct")
private String shortName;
@SerializedName("description_product")
private String descriptionProduct;
@SerializedName("altitude")
private String altitude;
@SerializedName("photo")
private String photo;

I just have to create the get and set and I would be ready to use the model. I need to know how to do in swift the same, maybe a library that helps me store data json in the same way that I do in android. Any comment would be very appreciated.

Upvotes: 2

Views: 2205

Answers (3)

Romulo BM
Romulo BM

Reputation: 751

With Alamofire you will get a key-value, an Dictionary<String,Any> or [String:Any]

So you can do the following with your dictionary:

var myProduct : Product?
if let price = myDictionary["price"] as? String{
    myProduct.price = price
}

With that example you can create a method to mapping the entire JSON into your struct. Maybe if you want to make it more scalable, you can create an enum with String raw values and use it as the key for the dictionary, some like:

enum productProperty : String{
    case Price = "price"
}
var myProduct : Product?
if let price = myDictionary[productProperty.Price] as? String{
    myProduct.price = price
}

And maybe create a more complex class to iterate trough the dictionary and check the key using the enum, but that implementation depends of your own skills.

Edit1:

To use't with alamofire, you need to get the jsonResponse of the request, some like that:

.request(yourURL, method: .get, parameters: yourParameter).responseJSON(options: .allowFragments , completionHandler: { response in
    if let object = response.result.value as? Dictionary<String,Any> {
        yourMethodToSave(object)
    }
})

and inside yourMethodToSave(_ object: Dictionary<String,Any>) you need to put the logic above.

Ps: The @sendtobo answer have the enum example that i tell that you can use to a more scalable mapping for your object

Upvotes: 0

D&#224;Ch&#250;n
D&#224;Ch&#250;n

Reputation: 5146

Feel free to use my gist here: Storage

You can use it like this:


let fileName = "Product.json"

extension Product {
    func store() {
        Storage.store(self, to: .documents, as: fileName)
    }

    static func retrieve() -> Product? {
        guard let product =  Storage.retrieve(fileName, from: .documents, as: Product.self) else {
            return nil
        }
        return product
    }
}

Upvotes: 0

sendtobo
sendtobo

Reputation: 36

The best way is to use the Coding Keys:

struct Product : Codable {
    let price : String?
    let nameusser : String?
    let favorite : Int
    let shortNameProduct : [Product]
    let description : [Galery]
    let alt : Product
    let success : Bool

    enum CodingKeys: String, CodingKey {
        case price = "price"
        case nameusser = "nameusser"
        case favorite = "favorite"
        case shortNameProduct = "short_nameProduct"
        case description = "description_product"
        case alt = "alt"
        case success = "success"
    }
}

The name of the enum case has to match the property name on the struct. This way you can define whatever keys you want without having to write any custom encoding or decoding code.

Upvotes: 2

Related Questions