7

As you know Codable is new stuff in swift 4, So we gonna move to this one from the older initialisation process for the Models. Usually we use the following Scenario

class LoginModal
{    
    let cashierType: NSNumber
    let status: NSNumber

    init(_ json: JSON)
    {
        let keys = Constants.LoginModal()

        cashierType = json[keys.cashierType].number ?? 0
        status = json[keys.status].number ?? 0
    }
}

In the JSON cashierType Key may missing, so we giving the default Value as 0

Now while doing this with Codable is quite easy, as following

class LoginModal: Coadable
{    
    let cashierType: NSNumber
    let status: NSNumber
}

as mentioned above keys may missing, but we don't want the Model Variables as optional, So How we can achieve this with Codable.

Thanks

AS Mackay
  • 2,831
  • 9
  • 19
  • 25
rinku khatri
  • 99
  • 1
  • 5
  • First of all don't use `NSNumber` in Swift, use `Int`, `Double` or `Bool`. Second of all in this case you have to write custom initializer. – vadian Nov 10 '18 at 08:12
  • @vadian Actually we wants to use codable to manage server response. So as mentioned we are already using custom initialiser, is there any way to handle all this with codable? – rinku khatri Nov 10 '18 at 08:28
  • You have to implement `init(from decoder:` and use `decodeIfPresent` for the affected properties to be able to assign default values. – vadian Nov 10 '18 at 08:34
  • Possible duplicate of [With JSONDecoder in Swift 4, can missing keys use a default value instead of having to be optional properties?](https://stackoverflow.com/questions/44575293/with-jsondecoder-in-swift-4-can-missing-keys-use-a-default-value-instead-of-hav) – Cristik Oct 01 '19 at 20:32

1 Answers1

12

Use init(from decoder: Decoder) to set the default values in your model.

struct LoginModal: Codable {

    let cashierType: Int
    let status: Int

    enum CodingKeys: String, CodingKey {
        case cashierType = "cashierType"
        case status = "status"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.cashierType = try container.decodeIfPresent(Int.self, forKey: .cashierType) ?? 0
        self.status = try container.decodeIfPresent(Int.self, forKey: .status) ?? 0
    }
}

Data Reading:

do {
        let data = //JSON Data from API
        let jsonData = try JSONDecoder().decode(LoginModal.self, from: data)
        print("\(jsonData.status) \(jsonData.cashierType)")
    } catch let error {
        print(error.localizedDescription)
    }
Sateesh Yemireddi
  • 4,289
  • 1
  • 20
  • 37
  • Thanks for the reply. Wants to ask one more thing that can we do this directly with the help of dictionary or firstly have convert it to data? – rinku khatri Nov 10 '18 at 10:03
  • We should pass the JSON data which is coming from API to _JSONDecoder_. – Sateesh Yemireddi Nov 10 '18 at 10:10
  • We are using firebase from there dictionary is coming in response, so can we us it directly or have to convert it in data. – rinku khatri Nov 10 '18 at 10:33
  • You can format the data from dictionary using JSONSerialization and pass it as an argument to JSONDecoder. – Sateesh Yemireddi Nov 10 '18 at 10:50
  • @Saleesh Why In above example you used the struct instead of class. Do there any specific reason? As I usually consider struct as value type Datatype. So passing through the view controllers will create copies for that each time, and its will be hard to update values at single instance – Rahish Apr 11 '19 at 12:03
  • @Rahish, We use struct for creating models for project because we do not want to modify its data which is getting from server, every time. On the other hand, if you would like to change the model data you can consider class as type for models. No problem..!! It's completely depends on the requirement of a project. More over, struct instances are allocated on stack, and class instances are allocated on heap, structs can sometimes be drastically faster. – Sateesh Yemireddi Jun 13 '19 at 11:46
  • Hi @Sateesh, Thanks for sharing your knowledge about struct and classes But our main concern is about Codable, We want modal value non-optional. as mentioned above, keys may missing, but we don't want the Model Variables as optional, So How we can achieve this with Codable. ex. cashierType = json[keys.cashierType].number ?? 0. Here we set 0 as default value, if will not set it to 0 and somehow the key may missed then the whole process will fail. – Rahish Jun 14 '19 at 05:40