0

I've JSON data, which is an array of dictionary, wherein the first item is different from the rest of the array items.

Sample JSON

[
  {
    "totalDays": 180,
    "totalWorkingDays": 148,
    "totalWorkingHours": "1184:00:00",
    "totalWorkedHours": "985:23:10",
    "totalShortageHours": "-199:37:50",
    "avgWorkingHours": "06:39:28(83%)",
    "avgShortageHours": "01:20:31(17%)",
    "totalAbsents": 13,
    "totalLeaves": 4
  },
  {
    "attendanceDayCount": 1,
    "attendanceDate": "21-Jan-19",
    "attendanceDay": "Monday"
  },
  {
    "attendanceDayCount": 2,
    "attendanceDate": "22-Jan-19",
    "attendanceDay": "Tuesday"
  },
  {
    "attendanceDayCount": 3,
    "attendanceDate": "23-Jan-19",
    "attendanceDay": "Wednesday"
  }
]

I'm using Codable and my struct looks like this

struct DashboardSummary : Codable {
    
   var totalDays : Int?
   var totalWorkingDays : Int?
   var totalWorkingHours : String?
   var totalWorkedHours : String?
   var totalShortageHours : String?
   var avgWorkingHours : String?
   var avgShortageHours : String?
   var totalAbsents : Int?
   var totalLeaves : Int?
   
} 

struct DaySummary : Codable {

   var attendanceDayCount : Int?
   var attendanceDate : String?
   var attendanceDay : String?    

}

EDIT: JSON Decoding from Network request method

DispatchQueue.main.async {
   if let responseObject = try? JSONDecoder().decode(Response.self, from: data) {
     print("responseObject", responseObject)
     completion(.success(responseObject))
   }
   else {
     let error = NSError(domain: "", code: 200, userInfo: [NSLocalizedDescriptionKey : "Failed to decode"])
     completion(.failure(error))
   }
 }

Things I've tried

  1. I passed 'DashboardSummary' struct as codable through my network request, which did give results for the first item and of-course nil value for the rest of the array.

  2. I tried init(from decoder: Decoder) and func encode(to encoder: Encoder) which unfortunately didn't work for me.

How can I get around this?

3
  • Related: stackoverflow.com/q/62907027/5133585 Commented Jul 16, 2020 at 0:48
  • 1
    Never, never ever ignore the Decoding error and create a custom completely meaningless NSError instance. Add a do - catch block and print the caught error instance. It tells you exactly what's wrong. Commented Jul 16, 2020 at 10:57
  • Point taken. There was no problem with @Sweeper's answer. The problem was with another struct. And scrapping custom NSError with do-catch point right to the actual error. Thanks Commented Jul 16, 2020 at 12:00

1 Answer 1

1

First, you need to create a third struct that can represent the array, for example:

struct Response : Codable {
    var dashboardSummary: DashboardSummary?
    var daySummaries: [DaySummary]
    
    enum CodingKeys: CodingKey {
        case dashboardSummary, daySummaries
    }
}

Then you need to implement init(from:) and encode(to:) to do custom coding.

You can use an unkeyedContainer to decode/encode it. When decoding, you keep decoding from the container while the container is not isAtEnd.

init(from decoder: Decoder) throws {
    var container = try decoder.unkeyedContainer()
    dashboardSummary = try container.decodeIfPresent(DashboardSummary.self)
    daySummaries = []
    while !container.isAtEnd {
        daySummaries.append(try container.decode(DaySummary.self))
    }
}

func encode(to encoder: Encoder) throws {
    var container = encoder.unkeyedContainer()
    try container.encode(dashboardSummary)
    for daySummary in daySummaries {
        try container.encode(daySummary)
    }
}

You can also consider making the properties let constants if you don't intend on changing them.

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

3 Comments

I made the third Struct as you instructed to manage the two types of array items. And added the init and encode from your answer. However, I'm getting a Failed to Decode error. Error Domain= Code=200 "Failed to decode" UserInfo= NSLocalizedDescription=Failed to decode}
@uzair I forgot to mention. You should decode Response.self. Did you do that? Otherwise, please edit the question to include a minimal reproducible example.
Yes, I did add Response.self for decode. I've edited my question. Added 'JSON decode' from the network request method.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.