2

I have been using codable in Swift from a long time and it has almost solved all the issues I had until I encountered the below mentioned issue. Suppose, the data coming from the API is something like this:

 { 
     "name": "ABC",
     "contactNo": "123", 
     "gender": "M", 
     "dob": "02-01-1998", 
     "qualitifcation": "XYZ"
   }

Now, I want to parse some part of this data in One model and some part in another model and have the reference of another model in the first model. For Eg:

  struct ModelOne: Codable {
    let name: String?
    let contactNo: String?
    let modelTwoRef: ModelTwo?
    }
    
    struct ModelTwo: Codable {
    let gender: String?
    let dob: String?
    let qualification: String?
    }

I am not able to solve this problem. It would be really helpful is someone can help with the same.

2
  • 1
    A custom init on ModelOne should do the job. Commented Jul 29, 2021 at 6:16
  • 2
    Implement init(from decoder: Decoder) in ModelOne, it will be pretty straightforward. See this article from Apple Commented Jul 29, 2021 at 6:18

4 Answers 4

2

You can solve this by overriding init(from:):

struct ModelOne: Codable {
    let name: String?
    let contactNo: String?
    let modelTwoRef: ModelTwo?

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.name = try container.decode(String.self, forKey: .name)
        self.contactNo = try container.decode(String.self, forKey: .contactNo)
        self.modelTwoRef = try ModelTwo(from: decoder)
    }
}

struct ModelTwo: Codable {
    let gender: String?
    let dob: String?
    let qualification: String?
}

Test sample:

let jsonStr = """
    {
    "name": "ABC",
    "contactNo": "123",
    "gender": "M",
    "dob": "02-01-1998",
    "qualification": "XYZ"
    }
    """

let jsonData = Data(jsonStr.utf8)

do {
    let model = try JSONDecoder().decode(ModelOne.self, from: jsonData)
    print(model)
} catch {
    print("Error: \(error)")
}

Small diff from your question which I guess was a typo: "qualification“ vs "qualitifcation".

Sign up to request clarification or add additional context in comments.

Comments

1

Create JSON decode function like below function

func decode<T: Decodable>(from data: Data, to decodableType: T.Type) -> T? {
    do {
        let decodedData = try decoder.decode(decodableType, from: data)
        return decodedData
    } catch let error {
        print(error)
    }
    return nil
}

check API response data nil or not using guard statement

guard let decoadedData = self.jsonHelper.decode(from: data, to: ModelOne.self) else {
                return
            }

1 Comment

This doesn’t answer the question
0

You need to implement decoding by hand in ModelOne and pass on the decoder. You can do this by implementing the init method of ModelOne like this:

struct ModelOne: Codable {
    let name: String?
    let contactNo: String?
    let modelTwoRef: ModelTwo?
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decodeIfPresent(String.self, forKey: .name)
        contactNo = try container.decodeIfPresent(String.self, forKey: .contactNo)
        modelTwoRef = try ModelTwo(from: decoder)
    }
    
    enum CodingKeys: String, CodingKey {
        case name, contactNo
    }
}

struct ModelTwo: Codable {
    let gender: String?
    let dob: String?
    let qualification: String?
}

I hope it solves your problem. /Martin

Comments

0
struct ModelOne: Codable {
    var name: String
    var contactNo: String
    var gender: String
    var dob: Date
    var qualification: String
}

let json = """
{
    "name": "ABC",
    "contactNo": "123",
    "gender": "M",
    "dob": "02.01.1998",
    "qualification": "XYZ"
}
""".data(using: .utf8)!

let formatter = DateFormatter()
formatter.dateFormat = "dd.MM.yy"

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
let response = try decoder.decode(ModelOne.self, from: json)

print("Name: \(response.name)")
print("Contact no: \(response.contactNo)")
print("Gender: \(response.gender)")
print("Date: \(response.dob)")
print("qualification \(response.qualification)")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.