vivin
vivin

Reputation: 1002

Decode using JSONDecoder Swift

What is the data model corresponding to the below json?

{ 
   dog:
   {
      type: "dog",
      logoLocation: "url1"
   },
   pitbull: 
   {
       type: "pitbull",
       logoLocation: "url2"
    }
}

This is a dictionary of dictionaries So I tried,

class PhotosCollectionModel: Codable {
    var photoDictionary: Dictionary<String, PhotoModel>?
}

class PhotoModel: Codable {
    var type: String?
    var logoLocation: String?
}

But it is not working. Any help please?

Upvotes: 1

Views: 2169

Answers (3)

Abishek Thangaraj
Abishek Thangaraj

Reputation: 923

Use the below struct for unwrapping the data

// MARK: - Response
struct Response: Codable {
    
    let dog, pitbull: Dog?
    
    enum CodingKeys:String, CodingKey {
        case dog
        case pitbull
    }

    init(from decoder: any Decoder) throws {
        let container = try? decoder.container(keyedBy: CodingKeys.self)
        dog = try? container?.decodeIfPresent(Dog.self, forKey: .dog)
        pitbull = try? container?.decodeIfPresent(Dog.self, forKey: .pitbull)
    }

}

// MARK: - Dog
struct Dog: Codable {
    
    let type, logoLocation: String?
    
    enum CodingKeys:String, CodingKey {
        case type
        case logoLocation
    }

    init(from decoder: any Decoder) throws {
        let container = try? decoder.container(keyedBy: CodingKeys.self)
        type = try? container?.decodeIfPresent(String.self, forKey: .type)
        logoLocation = try? container?.decodeIfPresent(String.self, forKey: .logoLocation)
    }
    
}

Use the below code for decode the json Data

   do {
        let dictonary = try JSONDecoder().decode([String:Dog].self,from:data)
// Or use this code
        let response = try JSONDecoder().decode(Response.self,from:data)
    }
    catch let error{
        print(error)
    }

Upvotes: 0

Joakim Danielson
Joakim Danielson

Reputation: 51882

I would skip the first class and keep

struct PhotoModel: Codable {
    let type: String
    let logoLocation: String
}

and then decode it like a dictionary

do {
    let decoder = JSONDecoder()
    let result = try decoder.decode([String: PhotoModel].self, from: data)
    result.forEach { (key,value) in
        print("Type: \(value.type), logo: \(value.logoLocation) (key: \(key))")
    }
} catch  {
    print(error)
}

Outputs

Type: dog, logo: url1 (key: dog)
Type: pitbull, logo: url2 (key: pitbull)

Are really both attributes optional, if not I suggest you remove any unnecessary ? in PhotoModel (I did)

Upvotes: 0

Shehata Gamal
Shehata Gamal

Reputation: 100503

You need

struct Root: Codable {
    let dog, pitbull: Dog
}

struct Dog: Codable {
    let type, logoLocation: String  // or let logoLocation:URL
}

Correct json

{
    "dog":
    {
        "type": "dog",
        "logoLocation": "url1"
    },
    "pitbull":
    {
        "type": "pitbull",
        "logoLocation": "url2"
    }
}

for dynamic

just use [String:Dog] in Decoder

    do {

        let res  = try JSONDecoder().decode([String:Dog].self,from:data)
    }
    catch {

        print(error)
    }

Upvotes: 3

Related Questions