I am not sure why but in the Bundle-Decodable file the last guard is getting triggered.
guard let loaded = try? decoder.decode(T.self, from: data) else {
fatalError("Failed to decode \(file) from bundle.")
}
I don't know if you need it to help me but here is all of my code,
ContentView:
import SwiftUI
struct ContentView: View {
let astronauts: [String: Astronaut] = Bundle.main.decode("astronauts.json")
let missions: [Mission] = Bundle.main.decode("missions.json")
let columns = [
GridItem(.adaptive(minimum: 150))
]
var body: some View {
NavigationView {
ScrollView {
LazyVGrid(columns: columns) {
ForEach(missions) { mission in
NavigationLink {
Text("Detail view")
} label: {
VStack {
Image(mission.image)
.resizable()
.scaledToFit()
.frame(width: 100, height: 100)
VStack {
Text(mission.displayName)
.font(.headline)
.foregroundColor(.white)
Text(mission.formattedLaunchDate)
.font(.caption)
.foregroundColor(.white.opacity(0.5))
}
.padding(.vertical)
.frame(maxWidth: .infinity)
.background(.lightBackground)
}
.clipShape(RoundedRectangle(cornerRadius: 10))
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(.lightBackground)
)
}
}
}
.padding([.horizontal, .bottom])
}
.navigationBarTitle("Moonshot")
.background(.darkBackground)
.preferredColorScheme(.dark)
}
}
}
Color-Theme
import Foundation
import SwiftUI
extension ShapeStyle where Self == Color {
static var darkBackground: Color {
Color(red: 0.1, green: 0.1, blue: 0.2)
}
static var lightBackground: Color {
Color(red:0.2, green: 0.2, blue: 0.3)
}
}
Astronaut
import Foundation
struct Astronaut: Codable, Identifiable {
let id: String
let name: String
let description: String
}
Bundle-Decodable
import Foundation
extension Bundle {
func decode<T: Codable>(_ file: String) -> T {
guard let url = self.url(forResource: file, withExtension: nil) else {
fatalError("Failed to locate \(file) in bundle.")
}
guard let data = try? Data(contentsOf: url) else {
fatalError("Failed to load \(file) from bundle.")
}
let decoder = JSONDecoder()
let formatter = DateFormatter()
formatter.dateFormat = "y-MM-dd"
decoder.dateDecodingStrategy = .formatted(formatter)
guard let loaded = try? decoder.decode(T.self, from: data) else {
fatalError("Failed to decode \(file) from bundle.")
}
return loaded
}
}
Mission
import Foundation
struct Mission: Codable, Identifiable {
struct CrewRole: Codable {
let name: String
let role: String
}
let id: Int
let launchDate: Date?
let crew: [CrewRole]
let description: String
var displayName: String {
"Apollo \(id)"
}
var image: String {
"apollo\(id)"
}
var formattedLaunchDate: String {
launchDate?.formatted(date: .abbreviated, time: .omitted) ?? "N/A"
}
}