Доступ к вложенному объекту из JSON, когда это число типа Dynami c, представленное в виде строки - PullRequest
1 голос
/ 20 января 2020

Я обращаюсь к данным из API с помощью XCode (10.2.1) и Swift (5.0) и столкнулся с проблемой, на которую не могу найти ответ. Я могу получить данные из всех других частей API, кроме одной, которая была названа числовой строкой «750», я не уверен, как получить эти данные, когда я не могу использовать переменную, которую может прочитать jsonDecoder?

Это пример того, что, как я знаю, не сработает, но дает представление о том, что я пытаюсь сделать.

class Images: Codable {
    let "750": String

    init("750": String){
        self."750" = "750"
    }
}

Вот фрагмент из API, который я пытаясь получить изображения от:

  "id": "069f7f26",
      "sku": "AP",
      "title": "Pizza",
      "description": "A really great pizza",
      "list_price": "9.95",
      "is_vatable": true,
      "is_for_sale": false,
      "age_restricted": false,
      "box_limit": 2,
      "always_on_menu": false,
      "volume": null,
      "zone": null,
      "created_at": "2017-03-06T10:52:43+00:00",
      "attributes": [
        {
          "id": "670f0e7c",
          "title": "Allergen",
          "unit": null,
          "value": "Products manufactured in a nut environment"
        },
        {
          "id": "c29e7",
          "title": "Weight",
          "unit": "g",
          "value": "300"
        }
      ],
      "tags": [

      ],
      "images": {
        "750": {
          "src": "https:\/\/some_website.co.uk\/cms\/product_image\some_image.jpg",
          "url": "https:\/\/some_website.co.uk\/cms\/product_image\some_image.jpg",
          "width": 750
        }
      }
    },

1 Ответ

1 голос
/ 20 января 2020

Я настроил пример, который лучше соответствует вашей ситуации, чтобы дать вам обзор того, как parse и получить динамический доступ к вашей информации JSON с типом данных Dictionary:

import Foundation

let jsonData = """
{
    "images": {
        "750": {
          "src": "https:\\/\\/some_website.co.uk/cms/product_image/some_image.jpg",
          "url": "https:\\/\\/some_website.co.uk/cms/product_image/some_image.jpg",
          "width": 750
        }
    }
}
"""

let json = jsonData.data(using: .utf8)!

public struct Results: Codable {
    public var images: [String:Image] = [:]

    enum CodingKeys: String, CodingKey {
        case images = "images"
    }
}

public struct Image: Codable {
    public var src: String = ""
    public var url: String = ""
    public var width: Int = 0

    enum CodingKeys: String, CodingKey {
        case src = "src"
        case url = "url"
        case width = "width"
    }
}

if let results = try? JSONDecoder().decode(Results.self, from: json) {
    let imagesDict = results.images
    for (key, value) in imagesDict {
        print("Key: \(key)")
        print("Value: \(value)")
    }
}

Если вы попробуете этот фрагмент, он напечатает следующий вывод:

Key: 750
Value: Image(src: "https://some_website.co.uk/cms/product_image/some_image.jpg", url: "https://some_website.co.uk/cms/product_image/some_image.jpg", width: 750)

Вы можете попробовать приведенный выше фрагмент кода онлайн, если скопируете, вставьте его здесь и запустите: http://online.swiftplayground.run/

### ОБНОВЛЕНИЕ (в ответ на комментарий)

В ответ на ваш комментарий мне было проще настроить другой пример, чтобы показать вам, как этого добиться с вашим точным примером кода, который вы поделились в самом комментарии.

Я оставил все как класс и просто добавил images, чтобы дать вам обзор того, как этого добиться.

В конце я бы предложил переименовать Products и Attributes в Product и Attribute. Также, если нет веских причин, по которым вы выбрали model равным class, просто измените их на struct, а также, если нет веских причин для сохранения большинства атрибутов каждой модели, которые дает optional это значение по умолчанию, как и в предыдущем примере, если вы всегда ожидаете, что некоторые значения / атрибуты будут там.

Вы можете попробовать запустить этот фрагмент также в http://online.swiftplayground.run, чтобы попробуйте:

import Foundation

let jsonData = """
{
    "data": [
        {
            "title": "titlex",
            "description": "descx",
            "list_price": "123,456",
            "attributes": [
                {
                    "title": "titlex",
                    "unit": "unitx",
                    "value": "valuex"
                }
            ],
            "images": {
                "750": {
                "src": "https:\\/\\/some_website.co.uk/cms/product_image/some_image.jpg",
                "url": "https:\\/\\/some_website.co.uk/cms/product_image/some_image.jpg",
                "width": 750
                }
            }
        }
    ]
}
"""

let json = jsonData.data(using: .utf8)!

class AllProducts: Codable {
    let data: [Products]

    init(data: [Products]) {
        self.data = data
    }
}

class Products: Codable {
    let title: String?
    let description: String?
    let list_price: String?
    let attributes: [Attributes]?
    let images: [String:Image]?

    init(title: String, description: String, list_price: String, attributes: [Attributes], images: [String:Image]) {
        self.title = title
        self.description = description
        self.list_price = list_price
        self.attributes = attributes
        self.images = images
    }
}

class Attributes: Codable {
    let title: String?
    let unit: String?
    let value: String?

    init(title: String, unit: String, value: String) {
        self.title = title
        self.unit = unit
        self.value = value
    }
}

class Image: Codable {
    let src: String?
    let url: String?
    let width: Int?

    init(src: String, url: String, width: Int) {
        self.src = src
        self.url = url
        self.width = width
    }
}

// parsing/decoding
if let results = try? JSONDecoder().decode(AllProducts.self, from: json) {
    if let imagesDict = results.data[0].images {

    // there is an "images" for product at position 0 (the only one in my json example)
        for (key, value) in imagesDict {
            print("Key: \(key)")
            print("Value src: \(value.src)")
            print("Value url: \(value.url)")
            print("Value width: \(value.width)")
        }
    }
}

Вывод

Key: 750
Value src: Optional("https://some_website.co.uk/cms/product_image/some_image.jpg")
Value url: Optional("https://some_website.co.uk/cms/product_image/some_image.jpg")
Value width: Optional(750)
...