I have ran into an issue with this, I am not sure what I am doing wrong for nothing to be displaying. I am pretty positive I am doing this correctly (well I guess I'm not) but I cannot figure out what I am doing wrong. I am new to Swift so I am learning still which is why I am taking it from this approach as I want to do this in the most simple way possible. So my question is, what part of this am I doing wrong?
SwiftUI Code:
//
// ContentView.swift
// APIExample
import SwiftUI
struct Response: Codable {
var articles: [Article]
}
struct Article: Codable, Identifiable {
var id = UUID()
var author: String
var title: String
}
struct ContentView: View {
@State private var articles = [Article]()
func loadData() async {
guard let url = URL(string: "https://newsapi.org/v2/top-headlines?sources=techcrunch&apiKey=APIKEY") else {
print("Invalid URL")
return
}
do {
let (data, _) = try await URLSession.shared.data(from: url)
if let decodedResponse = try? JSONDecoder().decode(Response.self, from: data) {
articles = decodedResponse.articles
}
} catch {
print("Invalid data")
}
}
var body: some View {
List(articles, id: \.id) { item in
VStack(alignment: .leading) {
Text(item.author)
.font(.headline)
Text(item.title)
}
}.task {
await loadData()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
JSON: https://pastebin.com/Zn4kY2BV
CodePudding user response:
The error you get is:
Invalid data: keyNotFound(CodingKeys(stringValue: "id", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "articles", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"id\", intValue: nil) (\"id\").", underlyingError: nil))
you could fix the error by supplying a custom decode init
struct Article: Codable, Identifiable {
var id = UUID()
var author: String
var title: String
enum CodingKeys: CodingKey {
case author
case title
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
author = try container.decode(String.self, forKey: .author)
title = try container.decode(String.self, forKey: .title)
}
}
CodePudding user response:
id
is in JSON, but not how you have specified it in your code:
struct Response: Codable {
var articles: [Article]
}
struct Source: Codable {
var id: String
var name: String
}
struct Article: Codable, Identifiable {
var source = Source
var author: String
var title: String
}
And for your ListView()
List(articles) { item in
VStack(alignment: .leading) {
Text(item.author)
.font(.headline)
Text(item.title)
}
}