2

Need to create object from JSON object

JSON Response from API

{
    "id": 1,
    "name": "Cricket",
    "slug": "cricket",
    "banner_image": "https://cricket.jpg",
    "icons": {
        "green": "http://localhost:8000/sport_icon_cricket_green.png",
        "grey": "http://localhost:8000/sport_icon_cricket_gray.png",
        "white": "http://localhost:8000/sport_icon_cricket_white.png",
        "black": "http://localhost:8000/sport_icon_cricket_black.png"
    }
},
{
    "id": 2,
    "name": "Baseball",
    "slug": "baseball",
    "banner_image": "https://baseball.jpg",
    "icons": {
        "green": "http://localhost:8000/sport_icon_baseball_green.png",
        "grey": "http://localhost:8000/sport_icon_baseball_gray.png",
        "white": "http://localhost:8000/sport_icon_baseball_white.png",
        "black": "http://localhost:8000/sport_icon_baseball_black.png"
    }
},

I created struct like below

Error on below linke struct ObjSportsList:Codable

struct ObjSportsList:Codable { // Error on this line -> Error : Type 'ObjSportsList' does not conform to protocol 'Decodable'

    var id:Int
    var name:String
    var slug:String
    var icons:ObjSportsIcon
}

struct ObjSportsIcon {
    var green:String
    var grey:String
    var white:String
    var black:String
}

Decode Like this

let decoderdec = JSONDecoder()
                        decoderdec.keyDecodingStrategy = .convertFromSnakeCase
                        // 2. Create Data from Response
                        let jsonData = try JSONSerialization.data(withJSONObject: jsonResponse["data"] as! [[String:Any]])

                        // 3 Convert Data to Object (Array) if don't user array then only pass ObjCountry.self
                        self.arrSports.removeAll()
                        self.arrSports = try decoderdec.decode([ObjSportsList].self, from: jsonData)

ERROR on decode line : Cannot assign value of type '[ObjSportsList]' to type '[[String : Any]]'

Update

// Error 2.Create Data from Response // This is Array of [[String:Any]] let jsonData = try JSONSerialization.data(withJSONObject: jsonResponse["data"] as! [[String:Any]])

4
  • you should conform the "ObjSportsIcon" struct with Codable protocol as well Commented Jun 14, 2019 at 4:53
  • ObjSportsIcon should be confirm to Codable. Commented Jun 14, 2019 at 4:53
  • Can you please provide example ? Commented Jun 14, 2019 at 4:54
  • Your error explains everything, your json response is dictionary while you are aspecting a array. Change you response to start from array Commented Jun 14, 2019 at 5:18

3 Answers 3

3

You were just missing Codable implementation with ObjSportsIcon class.

struct ObjSportsList : Codable {
    
    var id:Int
    var name:String
    var slug:String
    var icons:ObjSportsIcon
}

struct ObjSportsIcon : Codable {
    var green:String
    var grey:String
    var white:String
    var black:String
}

OR You can use the following code to make it proper:

public struct ObjSportsList : Codable {
    
    var id:Int
    var name:String
    var slug:String
    var icons:ObjSportsIcon
    
    public init(id: Int, name: String, slug: String, icons: ObjSportsIcon) {
        self.id = id
        self.name = name
        self.slug = slug
        self.icons = icons
    }
    
    public enum CodingKeys: String, CodingKey {
        case id
        case name
        case slug
        case icons
    }
}

public struct ObjSportsIcon : Codable {
    var green:String
    var grey:String
    var white:String
    var black:String
    
    public init(green: String, grey: String, white: String, black: String) {
        self.green = green
        self.grey = grey
        self.white = white
        self.black = black
    }
    
    public enum CodingKeys: String, CodingKey {
        case green
        case grey
        case white
        case black
    }
}

Change following line of code to solve your 2nd error:

self.arrSports = try decoderdec.decode(Array<ObjSportsList>.self, from: jsonData)

Update by Vivek :

I found my mistake and solution for the second error

Old code var arrSports:[[String:Any]] = []

New code var arrSports:[ObjSportsList] = []


You have to implement init(from decoder: Decoder) method to achieve the same. Note: You have to set default values to every property

struct ObjSportsIcon : Codable {
    var green:String
    var grey:String
    var white:String
    var black:String
    var pink:String
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.green = try container.decodeIfPresent(String.self, forKey: .green) ?? "green"
        self.grey = try container.decodeIfPresent(String.self, forKey: .grey) ?? "grey"
        self.white = try container.decodeIfPresent(String.self, forKey: .white) ?? "white"
        self.black = try container.decodeIfPresent(String.self, forKey: .black) ?? "black"
        self.pink = try container.decodeIfPresent(String.self, forKey: .pink) ?? "pink"
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you for answer, first error solved like declare struct, but still error on self.arrSports = try decoderdec.decode([ObjSportsList].self, from: jsonData) Error : Cannot assign value of type '[ObjSportsList]' to type '[[String : Any]]'
@Vivek Check Updated answer, you just have to change one line of code.
@Vivek You haven't mentioned the declaration of arrSport before :), Anyways Good that it solved.
Any way for optional key like 'pink' in icons:ObjSportsIcon ?
Any way for optional key like 'pink' in icons:ObjSportsIcon ?, I would like to add my own key like selected:Bool which is not received from API, I'll change selected key by selection of tableview and display selected key on tableview cell.
|
1

Well there are two options:

  1. old way - create init from your JSON
  2. convert JSON in to Data. In my case that option helps
let data = try JSONSerialization.data(withJSONObject: dictionary, options: [.fragmentsAllowed])

Comments

0

I don't know why are facing the issue because I have tried by just copy paste your code. Everythings work fine. Please refer below code.

Model Class:

struct ObjSportsList : Decodable {
    var id:String
    var name:String
    var slug:String
    var icons:ObjSportsIcon
}

struct ObjSportsIcon : Decodable {
    var green:String
    var grey:String
    var white:String
    var black:String
}

Parsing Code:

let decoderdec = JSONDecoder()
decoderdec.keyDecodingStrategy = .convertFromSnakeCase

let aryTemp = [[
        "id": "1",
        "name": "Cricket",
        "slug": "cricket",
        "banner_image": "https://cricket.jpg",
        "icons": [
            "green": "http://localhost:8000/sport_icon_cricket_green.png",
            "grey": "http://localhost:8000/sport_icon_cricket_gray.png",
            "white": "http://localhost:8000/sport_icon_cricket_white.png",
            "black": "http://localhost:8000/sport_icon_cricket_black.png"
    ]],[
        "id": "2",
        "name": "Baseball",
        "slug": "baseball",
        "banner_image": "https://baseball.jpg",
        "icons": [
            "green": "http://localhost:8000/sport_icon_baseball_green.png",
            "grey": "http://localhost:8000/sport_icon_baseball_gray.png",
            "white": "http://localhost:8000/sport_icon_baseball_white.png",
            "black": "http://localhost:8000/sport_icon_baseball_black.png"
        ]
    ]]

do {
    let jsonData = try JSONSerialization.data(withJSONObject: aryTemp)
    let arrSports = try decoderdec.decode([ObjSportsList].self, from: jsonData)        
    print(arrSports)
} catch let error {
    print(error)
}

5 Comments

There is lot of difference between json provided by OP and what you have mentioned in your code. so how you can say that you just copy pasted his code and everything is working fine
@Vikky I have just convert JSON Array to Swift Array syntax nothing else.
But OP's json response is not an array. see what error he mentioned
@Vikky Read question again. Also, If you are given full attention to code then you have noticed, OP is asked about Array.
Yes he mentioned this in his update, but the json he posted is invalid json.But if we assume that its array then everything works fine

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.