【问题标题】:Use keys from JSON object to parse data and display as a list使用 JSON 对象中的键解析数据并显示为列表
【发布时间】:2020-10-11 07:42:53
【问题描述】:

我有一个返回带有键的 JSON 对象的 API: http://acnhapi.com/v1/bugs

由于它不是数组,我想了解如何遍历它。我正在尝试通过使用它们的键 common_butterflyyellow_butterfly 等来获取错误名称“普通蝴蝶”和“黄色蝴蝶”等的列表。

我想显示common_butterfly.name.name-USen 的值,但针对每个错误。所以我的列表视图最终应该显示为:

  • 普通蝴蝶
  • 黄蝴蝶
  • 虎蝶

(按字母顺序排列将是一个奖励)

数据

import SwiftUI

struct Bugs: Codable, Identifiable {
    let id = UUID()
    var name: String
}

class FetchBugs: ObservableObject {
  @Published var bugs = [Bugs]()
     
    init() {
        let url = URL(string: "http://acnhapi.com/v1/bugs")!
        URLSession.shared.dataTask(with: url) {(data, response, error) in
            do {
                if let bugsData = data {
                    let decodedData = try JSONDecoder().decode([Bugs].self, from: bugsData)
                    DispatchQueue.main.async {
                        self.bugs = decodedData
                    }
                } else {
                    print("No data")
                }
            } catch {
                print("Error")
            }
        }.resume()
    }
}

列表

import SwiftUI

struct BugList: View {
    @ObservedObject var fetch = FetchBugs()
    var body: some View {
        VStack {
            List(fetch.bugs) { bug in
                VStack(alignment: .leading) {
                    Text(bug.name)
                }
            }
        }
    }
}

struct BugList_Previews: PreviewProvider {
    static var previews: some View {
        BugList()
    }
}

【问题讨论】:

  • 你的问题是什么,是关于 json 解码还是如何访问 bugs 数组/字典,还是关于 SwiftUI 部分?
  • 访问X.name.name-USen,其中 X 是 JSON 对象中的键。现在我列表中的 VStack 没有访问正确的字段。

标签: swift xcode swiftui swiftui-list


【解决方案1】:

使用此解决方案,您可以解码所有本地化名称:

struct Bug: Decodable, Identifiable {
    enum CodingKeys: String, CodingKey { case name }
    
    let id = UUID()
    var localizedNames: [String: String] = [:]
    
    var nameUSen: String {
        localizedNames["name-USen"] ?? "error"
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let names = try container.decode([String: String].self, forKey: .name)
        for (key, value) in names {
            localizedNames[key] = value
        }
    }
}

使用.sorted { $0.nameUSen < $1.nameUSen } 对您的数据进行排序

class FetchBugs: ObservableObject {
    @Published var bugs = [Bug]()

    init() {
        let url = URL(string: "http://acnhapi.com/v1/bugs")!
        URLSession.shared.dataTask(with: url) { data, response, error in
            do {
                if let bugsData = data {
                    let decodedData = try JSONDecoder().decode([String: Bug].self, from: bugsData)
                    DispatchQueue.main.async {
                        self.bugs = Array(decodedData.values).sorted { $0.nameUSen < $1.nameUSen }
                    }
                } else {
                    print("No data")
                }
            } catch {
                print(error)
            }
        }.resume()
    }
}

并显示USen 名称:

struct BugList: View {
    @ObservedObject var fetch = FetchBugs()
    var body: some View {
        VStack {
            List(fetch.bugs) { bug in
                VStack(alignment: .leading) {
                    Text(bug.nameUSen)
                }
            }
        }
    }
}

如果您想访问任何其他可以使用的名称:

bug.localizedNames["name-EUde"]!

【讨论】:

  • 这个逻辑是有道理的,但我无法使用这种方法呈现一个包含值的列表。你这边的数组是空的吗?
  • @OP 我在 Xcode 11.5 / Swift 5.2.4 / iOS 13.5 中测试了它(也在预览版中)。您是否尝试单独运行我的代码?
  • 通过预览在 xcode 11.4 上纯粹测试了您的代码。将更新并重试。
  • @OP 哦,抱歉...我使用了很久以前创建的测试项目,现在我看到我之前更改了 Info.plist。
  • 我没有在这个演示中添加它们,但是您可以在init(from decoder: Decoder)添加它们。
【解决方案2】:

这是一个说明按字母顺序获取所有错误名称的操场:

struct Bug: Decodable, Identifiable {
    let id: Int
    let name: Name

    struct Name: Decodable {
        let nameUSen: String

        enum CodingKeys: String, CodingKey {
            case nameUSen = "name-USen"
        }
    }
}

do {
    let butterflies = try Data(contentsOf: URL(string: "http://acnhapi.com/v1/bugs")!)
    let allBugs = try JSONDecoder().decode([String: Bug].self, from: butterflies)

    let bugs = Array(allBugs.values.sorted { $0.name.nameUSen < $1.name.nameUSen })
    bugs.forEach { print($0.name.nameUSen) }
} catch {
    print(error)
}

【讨论】:

  • 我似乎无法在 BugList 视图中将 name 称为 bug.name
  • 你必须使用bug.name.nameUSen,就像我的例子一样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-26
  • 1970-01-01
  • 2020-02-04
  • 2022-01-13
  • 1970-01-01
相关资源
最近更新 更多