Can anyone help solve the error here? I continue to get the fatal error in the ModelData.swift file: "Couldn't parse quotes.json as Array". I have validated the JSON file on JSONLint as well.
Here are the project files: LINK
I am new to SwiftUI so any help is very appreciated.
Model Data:
import Foundation
import Combine
final class ModelData: ObservableObject {
@Published var quotes: [Quote] = load("quotes.json")
}
func load<T: Decodable>(_ filename: String) -> T {
let data: Data
guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
else {
fatalError("Couldn't find \(filename) in main bundle")
}
do {
data = try Data(contentsOf: file)
} catch {
fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
}
do {
let decoder = JSONDecoder()
return try decoder.decode(T.self, from: data)
} catch {
fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
}
}
Model:
import SwiftUI
struct Quote: Codable, Identifiable, Hashable {
var id: Int
var readDate: Date?
var quote: String
var author: String
var isFavorited: Bool
var displayAuthor: String {
"- \(author)"
}
var formattedDate: String {
readDate?.formatted(date: .numeric, time: .omitted) ?? "N/A"
}
var dayDate: String {
readDate?.formatted(.dateTime.day()) ?? "N/A"
}
}
JSON File:
[
{
"id": 1,
"readDate": "11.12.2022",
"quote": "If you judge a fish by its ability to climb a tree then it will go its whole live beliving it's stupid.",
"author": "Albert Einstein",
"isFavorited": false
},
{
"id": 2,
"readDate": "11.13.2022",
"quote": "Do or do not. There is no try.",
"author": "Master Yoda",
"isFavorited": true
},
{
"id": 3,
"readDate": "11.14.2022",
"quote": "Learn as if you will live forever, live like you will die tomorrow.",
"author": "Mahatma Gandhi",
"isFavorited": false
},
{
"id": 4,
"readDate": "11.15.2022",
"quote": "When you change your thoughts, remember to also change your world.",
"author": "Norman Vincent Peale",
"isFavorited": false
},
{
"id": 5,
"readDate": "11.16.2022",
"quote": "Success is not final; failure if not fatal: It is the courage to continue that counts.",
"author": "Winston S. Churchill",
"isFavorited": false
},
{
"id": 6,
"readDate": "11.17.2022",
"quote": "Success is getting what you want, happiness is wanting what you get.",
"author": "W. P. Kinsella",
"isFavorited": false
},
{
"id": 7,
"readDate": "11.18.2022",
"quote": "Successs usually comes to those who are too busy looking for it.",
"author": "Henry David Thoreau",
"isFavorited": false
},
{
"id": 8,
"readDate": "11.19.2022",
"quote": "Don't let yesterday take up too much of today.",
"author": "Will Rogers",
"isFavorited": false
},
{
"id": 9,
"readDate": "11.20.2022",
"quote": "You miss 100% of the shots you don't take.",
"author": "Wayne Gretzky",
"isFavorited": true
}
]
Your json is formatting dates like "11.12.2022"
, which is MM.dd.yyyy
You need to provide this format to your JSONDecoder.
I generally use a DateFormatter extension for this:
extension DateFormatter {
static let jsonDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale.autoupdatingCurrent
formatter.dateFormat = "MM.dd.yyyy"
return formatter
}()
}
Then you simply pass this to your JSONDecoder, like this:
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(DateFormatter.jsonDateFormatter)
return try decoder.decode(T.self, from: data)
}