Wahab Khan Jadon
Wahab Khan Jadon

Reputation: 1176

Best approach to create Non-optional Codable with `default values` in swift

I know the basic concept of class and struct but which is more effective to create models for API to fetch data and tell me with pros and cons.

Previously i don't use optional for models. Instead i give it some value. ie

class CompanyInfo : Codable {
    var NameEn : String = ""
    var CityEn : String = ""
    var Website : String = ""
    var Email : String = ""
    var Phone : String = ""
    var Fax : String = ""
}

but when it get some null value from API. ie "Fax": null then App get crashed because it can't parse data with following line

let data = try JSONDecoder().decode(dataModel.self, from: dataSet)

what is the best way to deffine a model so i don't need to unwrap optional or give it default value.

Upvotes: 5

Views: 2675

Answers (3)

Maulik Pandya
Maulik Pandya

Reputation: 2220

There is no such answer for more efficient use of class or struct. that's depends on your need, app's demand and it's coding structure.

If you have to deal with the optionals at runtime this can be the best approach according to me.

I would prefer to use struct on this

struct YOUR_MODEL_NAME : Codable {

    var NameEn : String?
    var CityEn : String?
    var Website : String?
    var Email : String?
    var Phone : String?
    var Fax : String?

    enum CodingKeys: String, CodingKey {
        case NameEn = "YOUR_KEY_FOR_NameEn"
        case CityEn = "YOUR_KEY_FOR_CityEn"
        case Website = "YOUR_KEY_FOR_Website"
        case Email = "YOUR_KEY_FOR_Email"
        case Phone = "YOUR_KEY_FOR_Phone"
        case Fax = "YOUR_KEY_FOR_Fax"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        NameEn = try values.decodeIfPresent(String.self, forKey: .NameEn)
        CityEn = try values.decodeIfPresent(String.self, forKey: .CityEn)
        Website = try values.decodeIfPresent(String.self, forKey: .Website)
        Email = try values.decodeIfPresent(String.self, forKey: .Email)
        Phone = try values.decodeIfPresent(String.self, forKey: .Phone)
        Fax = try values.decodeIfPresent(String.self, forKey: .Fax)
    }
}

Upvotes: 0

Mojtaba Hosseini
Mojtaba Hosseini

Reputation: 119204

You can implement a custom decoder with default values:

class CompanyInfo : Codable {
    var NameEn: String
    var CityEn: String
    var Website: String
    var Email: String
    var Phone: String
    var Fax: String
    
    required init(from decoder: Decoder) throws {
        do {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            self.NameEn = try container.decodeIfPresent(String.self, forKey: .NameEn) ?? "Default"
            self.CityEn = try container.decodeIfPresent(String.self, forKey: .CityEn) ?? "Default"
            self.Website = try container.decodeIfPresent(String.self, forKey: .Website) ?? "Default"
            self.Email = try container.decodeIfPresent(String.self, forKey: .Email) ?? "Default"
            self.Phone = try container.decodeIfPresent(String.self, forKey: .Phone) ?? "Default"
            self.Fax = try container.decodeIfPresent(String.self, forKey: .Fax) ?? "Default"
        }
    }
}

Unrelated to question, but important Note:

In Swift, only Types names should start with a capital letter. If you continue naming variables like this, you will have a serious refactoring issue one day if you decide to use CoreData or working with other Swift developers.

Upvotes: 10

charlyatwork
charlyatwork

Reputation: 1197

Any future colleague will thank you if the data model reflects the JSON response of the API ("Don't make me think"). Furthermore, for now you don't want to have optional values - in 3 weeks you perhaps need them - then you have some ugly checks:

if companyInfo.fax == "default" {
   // Hey it's the default value but this indicates that the value is optional and nil
}

However, it's doable:

https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types

By the way - also have reading on Swift naming conventions regarding property names.

https://swift.org/documentation/api-design-guidelines/

Upvotes: 0

Related Questions