I use code that downloads and displays json data from a number of different public json sites such as Apple Music and jsonplaceholder. I have some test data in a bin at jsonbin.io. When I use the same code I cannot get the data to populate a list in SwiftUI. The test data is a public json and is non-sensitive. Any idea what I am doing wrong?
struct Facility: Codable, Identifiable {
var id: String
var facilityName: String
}
struct FacilityView: View {
@State private var facilities = [Facility]()
var body: some View {
NavigationView {
List(facilities, id: \.id) {item in
VStack {
Text(item.id)
.font(.headline)
Text(item.facilityName)
}
}
.navigationTitle("Facilities")
.task {
await fetchData()
}
}
}
func fetchData() async {
guard let url = URL(string: "https://api.jsonbin.io/v3/b/66130dbead19ca34f85689bc") else {
print("URL does not work")
return
}
do {
let (data, _) = try await URLSession.shared.data( from: url)
if let decodedResponse = try? JSONDecoder().decode([Facility].self, from: data) {
facilities = decodedResponse
}
} catch {
print("Data not valid")
}
}
}
#Preview {
FacilityView()
}
The response you get from the server is not an array [Facility]
.
So trying to decode this gives you an error that you should print, as
shown in the example code.
Try this approach using a set of models that match the json data.
Note, don't use try?
and print the actual error print("Data not valid \(error)")
struct ServerResponse: Codable {
let record: [Facility]
let metadata: Metadata
}
struct Metadata: Codable {
let id: String
let metaPrivate: Bool
let createdAt: String
enum CodingKeys: String, CodingKey {
case id
case metaPrivate = "private"
case createdAt
}
}
struct Facility: Codable, Identifiable {
var id: String
var facilityName: String
}
struct ContentView: View {
var body: some View {
FacilityView()
}
}
struct FacilityView: View {
@State private var facilities = [Facility]()
var body: some View {
NavigationView {
List(facilities) { item in
VStack {
Text(item.id).font(.headline)
Text(item.facilityName)
}
}
.navigationTitle("Facilities")
.task {
await fetchData()
}
}
}
func fetchData() async {
guard let url = URL(string: "https://api.jsonbin.io/v3/b/66130dbead19ca34f85689bc") else {
print("URL does not work")
return
}
do {
let (data, _) = try await URLSession.shared.data( from: url)
let decodedResponse = try JSONDecoder().decode(ServerResponse.self, from: data)
facilities = decodedResponse.record
} catch {
print("Data not valid \(error)") // <--- important
}
}
}