Reputation: 2365
I have an API that returns a JSON object with keys: http://acnhapi.com/v1/bugs
Since it's not an array, I'd like to understand how to traverse it. I am trying to get a list of the bug names "common butterfly" and "yellow butterfly" etc. by using their keys common_butterfly
and yellow_butterfly
etc.
I want to display the value of common_butterfly.name.name-USen
, but for each bug. So my list view should ultimately be displayed as:
(Alphabetical would be a bonus)
data
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()
}
}
list
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()
}
}
Upvotes: 0
Views: 855
Reputation: 54426
With this solution you can decode all your localised names:
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
}
}
}
Use .sorted { $0.nameUSen < $1.nameUSen }
to sort your data:
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()
}
}
And display the USen
name:
struct BugList: View {
@ObservedObject var fetch = FetchBugs()
var body: some View {
VStack {
List(fetch.bugs) { bug in
VStack(alignment: .leading) {
Text(bug.nameUSen)
}
}
}
}
}
If you'd ever want to access any other name you can use:
bug.localizedNames["name-EUde"]!
Upvotes: 1
Reputation: 17844
Here's a playground that illustrates getting all bug's names in alphabetical order:
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)
}
Upvotes: 0