1

Here is my JSON

{
    "myItems": {
        "item1name": [{
            "url": "google.com",
            "isMobile": true,
            "webIdString": "572392"
        }, {
            "url": "hulu.com",
            "isMobile": false,
            "webIdString": "sad1228"
        }],
        "item2name": [{
            "url": "apple.com",
            "isMobile": true,
            "webIdString": "dsy38ds"
        }, {
            "url": "Facebook.com",
            "isMobile": true,
            "webIdString": "326dsigd1"
        }, {
            "url": "YouTube.com",
            "isMobile": true,
            "webIdString": "sd3dsg4k"
        }]
    }
}

The json can have multiple items (such as item1name, item2name, item3name,...) and each item can have multiple objects (the example has 2 objects for the first item and 3 objects for the second item).

Here is the structure I want it saved to (incomplete):

struct ServerResponse: Decodable {
    let items: [MyItem]?
}

struct MyItem: Decodable {
    let itemName: String?
    let url: String?
    let isMobile: Bool?
    let webIdString: String?
}

In the example above, it would mean that the items list should have five MyItem objects. For example, these would be the MyItem objects:

#1: itemName: item1name, url: google.com, isMobile: true, webIdString: 572392

#2: itemName: item1name, url: hulu.com, isMobile: false, webIdString: sad1228

#3: itemName: item2name, url: apple.com, isMobile: true, webIdString: dsy38ds

#4: itemName: item2name, url: Facebook.com, isMobile: true, webIdString: 326dsigd1

#5: itemName: item2name, url: YouTube.com, isMobile: true, webIdString: sd3dsg4k

What would be the best way for me to do this using Decodable? Any help would be appreciated. I think this may be similar to this problem: How to decode a nested JSON struct with Swift Decodable protocol?

Ethan Yim
  • 85
  • 1
  • 6

2 Answers2

0

Use below code to decode nested JSON for your requirement:

import Foundation

// MARK: - Websites
struct Websites: Codable {
    var myItems: MyItems
}

// MARK: - MyItems
struct MyItems: Codable {
    var item1Name, item2Name: [ItemName]
    enum CodingKeys: String, CodingKey {
        case item1Name = "item1name"
        case item2Name = "item2name"
    }
}

// MARK: - ItemName
struct ItemName: Codable {
    var url: String
    var isMobile: Bool
    var webIDString: String
    enum CodingKeys: String, CodingKey {
        case url, isMobile
        case webIDString = "webIdString"
    }
}

NOTE: change the name of the variables according to your need.

EDIT

If you're still facing issue, use this app to convert your JSON to Struct:

Quick Type

Nirmit Dagly
  • 1,272
  • 1
  • 12
  • 25
  • Does this work if I don't know how many itemNames I will receive? I might have just `item1Name` and `item2Name`. Or I might have 5. Or I might have just 1. It depends on the server response. – Ethan Yim May 18 '21 at 02:04
  • If there are many item names, then update the struct MyItems to var itemName: [ItemName] enum CodingKeys: String, CodingKeys { case itemName } – Nirmit Dagly May 18 '21 at 02:26
0

Here is the structure you are after:

struct Websites: Decodable {
    let items: [Item]

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: Key.self)
        items = try container.decode([String: [Item]].self, forKey: .myItems).values.flatMap { $0 }
    }

    private enum Key: String, CodingKey {
        case myItems
    }
}

struct Item: Decodable {
    let url: String
    let isMobile: Bool
    let webIdString: String
}
Daniel T.
  • 32,821
  • 6
  • 50
  • 72