Swiftui结构和解码JSON

发布于 2025-02-09 05:51:08 字数 3860 浏览 3 评论 0原文

使用urlsession从我的自定义API中获取水晶数据。尝试按标题列出。

我知道这里有些不正确,但不确定是什么。整个过程中,JSON词典解码,但没有运气。

响应 struct多余的吗?还是可以简单地解码[string:Crystal]jsondecoder() ?任何方向和建议都得到赞赏。我知道如何使用阵列做到这一点,但是字典正在绊倒我。

获取https://lit-castle-74820.herokuapp.com/api/crystals

{
  "amethyst": {
    "composition": "silicon dioxide",
    "formation": "forms when gas bubbles occur in lava and become trapped",
    "colour": "purple",
    "metaphysical": [
      "calming",
      "healing",
      "especially for headaches",
      "fatigue, & anxiety"
    ]
  },
  "clear quartz": {
    "composition": "silicon dioxide",
    "formation": "forms when gas bubbles occur in lava and become trapped",
    "colour": "colourless or appears white",
    "metaphysical": "master healer for all ailments; amplifies the healing vibration of other stones placed nearby"
  },
  "moss agate": {
    "composition": "silicon dioxide, commonly featuring manganese or iron",
    "formation": "formed from weathered volcanic rock",
    "colour": "colourless with specks of white, green, blue, or brown",
    "metaphysical": [
      "gentle healing",
      "promotes tranquility",
      "cures physical ailments (inflammation, cold & flu)"
    ]
  },
  "carnelian": {
    "composition": "silicon dioxide with iron impurity",
    "formation": "formed from a combination of the silica minerals quartz and moganite",
    "colour": "orange or red often featuring yellow",
    "metaphysical": [
      "promotes life-force",
      "vitality",
      "energizes body and mind"
    ]
  },
  "spirit quartz": {
    "composition": "silicon dioxide",
    "formation": "forms when gas bubbles occur in lava and become trapped",
    "colour": "purple, yellowish brown, light grey",
    "metaphysical": [
      "assists in spiritual journey",
      "uplifts and promotes vibration"
    ]
  },
  "amazonite": {
    "composition": "potassium feldspar",
    "formation": "formed in deep sea igneous rocks that cool very slowly",
    "colour": "blue or green with white speckles or lines",
    "metaphysical": [
      "Soothes anxiety and overthinking",
      "helps heal emotional trauma"
    ]
  },
  "tourmaline": {
    "composition": "silicate of boron and aluminum",
    "formation": "Pegmatite pockets underground that slowly cool and form crystals",
    "colour": "black or pink",
    "metaphysical": [
      "repels negative energy",
      "highly protective"
    ]
  },
  "pyrite": {
    "composition": "iron sulfide",
    "formation": "forms in sedimentary rocks in low oxygen environments",
    "colour": "gold",
    "metaphysical": [
      "abundance",
      "good luck",
      "emotional strength"
    ]
  }
}
struct Response: Codable {
    let crystals: [String:Crystal]
}

struct Crystal: Codable, Identifiable {
    var id = UUID()
    let composition, formation, color: String
    let metaphysical: [String]
}

struct ContentView: View {
    @State private var crystals: [String:Crystal] = [:]
    
    var body: some View {
        List(crystals) { crystal in
            (crystal.key)
        }.onAppear(perform: loadData)
    }
    
    func loadData() {
        guard let url = URL(string: "https://lit-castle-74820.herokuapp.com/api/crystals") else { return }
        URLSession.shared.dataTask(with: url) { data, _, error in
            guard let data = data else { return }
            do {
                let decodedResponse = try JSONDecoder().decode(Response.self, from: data)
                DispatchQueue.main.async {
                  self.crystals = decodedResponse.crystals
               }
            } catch let jsonError as NSError {
              print("JSON decode failed: \(jsonError)")
            }
        }.resume()
    }
}

Using URLSession to get crystal data from my custom API. Trying to list by title.

I know something's incorrect here but not sure what. Looked all over SO for JSON dictionary decoding but no luck.

Is a Response struct superfluous or can I simply decode [String:Crystal] with JSONDecoder()? Any and all direction and suggestion is appreciated. I knew how to do this with arrays but dictionaries are tripping me up.

GET https://lit-castle-74820.herokuapp.com/api/crystals

{
  "amethyst": {
    "composition": "silicon dioxide",
    "formation": "forms when gas bubbles occur in lava and become trapped",
    "colour": "purple",
    "metaphysical": [
      "calming",
      "healing",
      "especially for headaches",
      "fatigue, & anxiety"
    ]
  },
  "clear quartz": {
    "composition": "silicon dioxide",
    "formation": "forms when gas bubbles occur in lava and become trapped",
    "colour": "colourless or appears white",
    "metaphysical": "master healer for all ailments; amplifies the healing vibration of other stones placed nearby"
  },
  "moss agate": {
    "composition": "silicon dioxide, commonly featuring manganese or iron",
    "formation": "formed from weathered volcanic rock",
    "colour": "colourless with specks of white, green, blue, or brown",
    "metaphysical": [
      "gentle healing",
      "promotes tranquility",
      "cures physical ailments (inflammation, cold & flu)"
    ]
  },
  "carnelian": {
    "composition": "silicon dioxide with iron impurity",
    "formation": "formed from a combination of the silica minerals quartz and moganite",
    "colour": "orange or red often featuring yellow",
    "metaphysical": [
      "promotes life-force",
      "vitality",
      "energizes body and mind"
    ]
  },
  "spirit quartz": {
    "composition": "silicon dioxide",
    "formation": "forms when gas bubbles occur in lava and become trapped",
    "colour": "purple, yellowish brown, light grey",
    "metaphysical": [
      "assists in spiritual journey",
      "uplifts and promotes vibration"
    ]
  },
  "amazonite": {
    "composition": "potassium feldspar",
    "formation": "formed in deep sea igneous rocks that cool very slowly",
    "colour": "blue or green with white speckles or lines",
    "metaphysical": [
      "Soothes anxiety and overthinking",
      "helps heal emotional trauma"
    ]
  },
  "tourmaline": {
    "composition": "silicate of boron and aluminum",
    "formation": "Pegmatite pockets underground that slowly cool and form crystals",
    "colour": "black or pink",
    "metaphysical": [
      "repels negative energy",
      "highly protective"
    ]
  },
  "pyrite": {
    "composition": "iron sulfide",
    "formation": "forms in sedimentary rocks in low oxygen environments",
    "colour": "gold",
    "metaphysical": [
      "abundance",
      "good luck",
      "emotional strength"
    ]
  }
}
struct Response: Codable {
    let crystals: [String:Crystal]
}

struct Crystal: Codable, Identifiable {
    var id = UUID()
    let composition, formation, color: String
    let metaphysical: [String]
}

struct ContentView: View {
    @State private var crystals: [String:Crystal] = [:]
    
    var body: some View {
        List(crystals) { crystal in
            (crystal.key)
        }.onAppear(perform: loadData)
    }
    
    func loadData() {
        guard let url = URL(string: "https://lit-castle-74820.herokuapp.com/api/crystals") else { return }
        URLSession.shared.dataTask(with: url) { data, _, error in
            guard let data = data else { return }
            do {
                let decodedResponse = try JSONDecoder().decode(Response.self, from: data)
                DispatchQueue.main.async {
                  self.crystals = decodedResponse.crystals
               }
            } catch let jsonError as NSError {
              print("JSON decode failed: \(jsonError)")
            }
        }.resume()
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

画中仙 2025-02-16 05:51:08

这是一个奇怪的API。您面临的问题在Crystal struct中。 形而上学似乎是String的数组,但在至少一种情况下,它是一个简单的String

编辑:

由于这是自定义API,您应该编辑它并返回String的数组,即使集合中只有一个元素。

另外:

  • 您的解码方法不起作用,因为JSON中没有顶级元素。它是SA [String:Crystal]
  • 您的struct color - > 颜色

然后您可以使用:

try JSONDecoder().decode([String:Crystal].self, from: data)

原始:

如果此数据是静态的(不更改),则可以逃脱以下解决方案:

struct Response: Codable {
    let amethyst, mossAgate, carnelian, spiritQuartz, amazonite, tourmaline, pyrite: GemWithArray
    let clearQuartz: GemWithoutArray

    enum CodingKeys: String, CodingKey {
        case amethyst
        case clearQuartz = "clear quartz"
        case mossAgate = "moss agate"
        case carnelian
        case spiritQuartz = "spirit quartz"
        case amazonite, tourmaline, pyrite
    }
}

struct GemWithArray: Codable {
    let composition, formation, colour: String
    let metaphysical: [String]
}

struct GemWithoutArray: Codable {
    let composition, formation, colour, metaphysical: String
}

并将其解码:

try JSONDecoder().decode(Response.self, from: data)

但是有一种方法可以使此更强大的方法和能够将其视为[String:gemwitharray]。您需要在gemwitharray struct中使用自定义初始化器。在其中尝试将形而上学解码为[String],如果失败,则创建数组,解码并将其作为string附加。

struct GemWithArray: Codable {
    let composition, formation, colour: String
    let metaphysical: [String]
    
    enum CodingKeys: String, CodingKey{
        case composition, formation, colour, metaphysical
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        composition = try container.decode(String.self, forKey: .composition)
        formation = try container.decode(String.self, forKey: .formation)
        colour = try container.decode(String.self, forKey: .colour)
        
        if let metaphysical = try? container.decode([String].self, forKey: .metaphysical){
            self.metaphysical = metaphysical
        } else{
            metaphysical = [try container.decode(String.self, forKey: .metaphysical)]
        }
    }
}

并像:

try JSONDecoder().decode([String:GemWithArray].self, from: data)

This is a somewhat strange API. The problem you are facing is within the Crystal struct. metaphysical seems to be an array of String but in at least one case it is a simple String.

Edit:

As this is a custom API you should edit it and return an array of String even if there is only one element in the collection.

In addition:

  • Your decoding approach does not work as there is no top element in the JSON. It´s a [String:Crystal].
  • You have a typo in your struct color -> colour

Then you can use:

try JSONDecoder().decode([String:Crystal].self, from: data)

Original:

If this data is static (does not change) you could get away with the following solution:

struct Response: Codable {
    let amethyst, mossAgate, carnelian, spiritQuartz, amazonite, tourmaline, pyrite: GemWithArray
    let clearQuartz: GemWithoutArray

    enum CodingKeys: String, CodingKey {
        case amethyst
        case clearQuartz = "clear quartz"
        case mossAgate = "moss agate"
        case carnelian
        case spiritQuartz = "spirit quartz"
        case amazonite, tourmaline, pyrite
    }
}

struct GemWithArray: Codable {
    let composition, formation, colour: String
    let metaphysical: [String]
}

struct GemWithoutArray: Codable {
    let composition, formation, colour, metaphysical: String
}

And decoding it like:

try JSONDecoder().decode(Response.self, from: data)

But there is a way to make this more robust and capable of treating it as [String:GemWithArray]. You would need to use a custom initializer in the GemWithArray struct. In it try to decode metaphysical to an [String] and if it fails create an array, decode and append it as String.

struct GemWithArray: Codable {
    let composition, formation, colour: String
    let metaphysical: [String]
    
    enum CodingKeys: String, CodingKey{
        case composition, formation, colour, metaphysical
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        composition = try container.decode(String.self, forKey: .composition)
        formation = try container.decode(String.self, forKey: .formation)
        colour = try container.decode(String.self, forKey: .colour)
        
        if let metaphysical = try? container.decode([String].self, forKey: .metaphysical){
            self.metaphysical = metaphysical
        } else{
            metaphysical = [try container.decode(String.self, forKey: .metaphysical)]
        }
    }
}

and decoding it like:

try JSONDecoder().decode([String:GemWithArray].self, from: data)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文