Как правильно анализировать вложенные данные JSON с помощью Swift? - PullRequest
1 голос
/ 18 октября 2019

Я новичок в разработке на Swift и iOS и в настоящее время изучаю, как работать с данными JSON.

Я пытаюсь проанализировать вложенные данные JSON и отобразить следующий вывод:

White hex value is #ffffff
Black hex value is #000000
Gray10 hex value is #f5f7f8
Gray20 hex value is #e8eced
Gray30 hex value is #d5d9db
Gray40 hex value is #b6bec2
Gray50 hex value is #8e999e
Gray60 hex value is #69757a
Gray70 hex value is #495257
Gray80 hex value is #333a3d
Gray90 hex value is #1f2426
Purple10 hex value is #ffc7f2
Purple20 hex value is #f59de2
Purple30 hex value is #e07ecb
Purple40 hex value is #d160b7
Purple50 hex value is #b34fa0
Purple60 hex value is #964286
Purple70 hex value is #773569
Purple80 hex value is #5b284f
Purple90 hex value is #401c36

Я могу разобрать простой файл JSON, например такой:

{
  "color": {
    "white": { "value": "#fff" },
    "black": { "value": "#000" }
  }
}

Однако я не могу понять, как правильно декодировать вложенные данные (см. Ниже) в structs и объединить gray и purple клавиши с их числовыми intensity клавишами (10-90), как видно из желаемого результата выше.

Вот мой код игровой площадки свложенные данные JSON, которые не работают:

import Foundation

let json = """
{
  "color": {
    "white": { "value": "#fff" },
    "black": { "value": "#000" },
    "gray": {
      "10": { "value": "#f5f7f8" },
      "20": { "value": "#e8eced" },
      "30": { "value": "#d5d9db" },
      "40": { "value": "#b6bec2" },
      "50": { "value": "#8e999e" },
      "60": { "value": "#69757a" },
      "70": { "value": "#495257" },
      "80": { "value": "#333a3d" },
      "90": { "value": "#1f2426" }
    },
    "purple": {
      "10": { "value": "#ffc7f2" },
      "20": { "value": "#f59de2" },
      "30": { "value": "#e07ecb" },
      "40": { "value": "#d160b7" },
      "50": { "value": "#b34fa0" },
      "60": { "value": "#964286" },
      "70": { "value": "#773569" },
      "80": { "value": "#5b284f" },
      "90": { "value": "#401c36" }
    }
  }
}
""".data(using: .utf8)!

struct color: Codable {
  let value: String
  struct intensity {
    let value: String
  }
}

struct Entry: Codable {
  let color: [String: color]
}

let jsonDecoder = JSONDecoder()

do {
  let parsedJSON = try jsonDecoder.decode(Entry.self, from: json)
  for color in parsedJSON.color {
    print("\(color.key) hex value is \(color.value.value)")
  }
}

В конечном итоге эта функциональность в конечном итоге окажется в приложении для iOS.

(Частичные) данные JSON, показанные в коде выше, являются фактическими производственными данными. Он предоставляется мне в этом формате. Поэтому я не могу изменить способ определения или вложения данных JSON.

Буду признателен за некоторые рекомендации о том, как анализировать вложенные данные JSON и отображать данные, как показано выше.

Ответы [ 2 ]

1 голос
/ 18 октября 2019

Я использовал JSONSerialization и две структуры для этого, ColorData и ColorSaturation, и обработал большую часть преобразования в init для ColorData

struct ColorData {
    let name: String
    let values: [ColorSaturation]

    init?(name: String, values: Any) {
        self.name = name
        if let single = values as? [String: String] {
            guard let colorValue = single["value"] else { return nil }
            self.values = [ColorSaturation(level: nil, value: colorValue)]
        } else if let colorValues = values as? [String: [String: String]] {
            var values = [ColorSaturation]()
            for (key, colorValue) in colorValues {
                guard let level = Int(key), let value = colorValue["value"] else { continue }
                values.append(ColorSaturation(level: level, value: value))
            }
            self.values = values
        } else {
            return nil
        }
    }
}

struct ColorSaturation {
    let level: Int?
    let value: String
}

И декодирование было сделано следующим образом

do {
    if let result = try JSONSerialization.jsonObject(with: data) as? [String: [String: Any]] {
    let colors = result["color"].map { $0.map {colorData in ColorData(name: colorData.key, values: colorData.value) }}

    print(colors)
    }
} catch {
    print(error)
}
1 голос
/ 18 октября 2019

Если вы не знаете, какими будут названия цветов, вы не сможете использовать Codable. Однако у вас может быть некоторая логика декодирования для создания массива структуры, которую вы определяете из json выше. Пример кода игровой площадки может быть таким, как приведенный ниже.

import UIKit

struct MyColor {
    let name: String
    let value: String

    var console: String {
        return name + " hex value is " + value
    }
}

let json = "{\"color\":{\"white\":{\"value\":\"#fff\"},\"black\":{\"value\":\"#000\"},\"gray\":{\"10\":{\"value\":\"#f5f7f8\"},\"20\":{\"value\":\"#e8eced\"},\"30\":{\"value\":\"#d5d9db\"},\"40\":{\"value\":\"#b6bec2\"},\"50\":{\"value\":\"#8e999e\"},\"60\":{\"value\":\"#69757a\"},\"70\":{\"value\":\"#495257\"},\"80\":{\"value\":\"#333a3d\"},\"90\":{\"value\":\"#1f2426\"}},\"purple\":{\"10\":{\"value\":\"#ffc7f2\"},\"20\":{\"value\":\"#f59de2\"},\"30\":{\"value\":\"#e07ecb\"},\"40\":{\"value\":\"#d160b7\"},\"50\":{\"value\":\"#b34fa0\"},\"60\":{\"value\":\"#964286\"},\"70\":{\"value\":\"#773569\"},\"80\":{\"value\":\"#5b284f\"},\"90\":{\"value\":\"#401c36\"}}}}"

func parse() throws -> [MyColor] {
    var myColors: [MyColor] = []
    if let data = json.data(using: .utf8) {
        if let root = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String:Any] {
            if let colors = root["color"] as? [String:Any] {
                for color in colors.keys {
                    if let valueNode = colors[color] as? [String:String] {
                        if let value = valueNode["value"] {
                            myColors.append(MyColor(name: color, value: value))
                        }
                    } else if let variants = colors[color] as? [String:[String:String]] {
                        for key in variants.keys {
                            if let variant = variants[key] {
                                if let value = variant["value"] {
                                    myColors.append(MyColor(name: color + key, value: value))
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return myColors
}

if let colors = try? parse() {
    for color in colors {
        print(color.console)
    }
}

Надеюсь, это поможет.

...