There is a lot of code in the Moonshot Project, and I'm honestly confused over this line.
I just finished everything before the last AstronautView. When I run the app, Xcode gives me this. Nothing else.
When I run the simulator, and click an icon to show the details, the app gets stuck, and then the above message pops out. Clearly, the detailed view is not working properly.
Any idea what I can do here?
MoonshitApp:
import SwiftUI
@main
struct MoonshotApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
ContentView:
import SwiftUI
// with an extension on Bundle, that's all it takes to get a [String: Astronaut] dictionary.
// add a Type Annotation to let Swift know what type our return will be
let astronauts: [String: Astronaut] = Bundle.main.decode("astronauts.json")
let missions: [Mission] = Bundle.main.decode("missions.json")
struct ContentView: View {
// note, this is an Array
let columns = [
GridItem(.adaptive(minimum: 150))
]
var body: some View {
NavigationView {
ScrollView {
LazyVGrid(columns: columns) {
ForEach(missions) {mission in
NavigationLink {
MissionView(mission: mission, astronauts: astronauts)
} label: {
VStack {
Image(mission.image)
.resizable()
.scaledToFit()
.frame(width: 100, height: 100)
.padding()
VStack {
Text(mission.displayName).font(.headline)
.font(.headline)
.foregroundColor(.white)
Text(mission.formattedLaunchDate).font(.headline).font(.caption)
.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])
}
.navigationTitle("Moonshot")
.background(.darkBackground)
// "Moonshot" will appear black or white depending on whether the user is in light mode or dark mode
.preferredColorScheme(.dark)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Mission View
import SwiftUI
struct MissionView: View {
// a mission property so we can show the mission badge and description
let mission : Mission
struct CrewMember {
let role : String
let astronaut : Astronaut
}
let crew : [CrewMember]
init(mission: Mission, astronauts: [String : Astronaut]) {
self.mission = mission
self.crew = mission.crew.map { member in
if let astronaut = astronauts[member.name] {
return CrewMember(role: member.role, astronaut: astronaut)
}
else {
fatalError("Missing \(member.name)")
}
}
}
var body: some View {
GeometryReader {geometry in
ScrollView {
VStack {
Image(mission.image)
.resizable()
.scaledToFit()
.frame(maxWidth: geometry.size.width * 0.6)
VStack(alignment: .leading) {
Text("Mission Highlights")
.font(.title.bold())
.padding(.bottom, 5)
Text(mission.description)
}
.padding(.horizontal)
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(crew, id : \.role) { crewMember in
NavigationLink {
Text("Astronaut Details")
} label: {
HStack {
Image(crewMember.astronaut.id)
.resizable()
.frame(width: 104, height: 72)
.clipShape(Capsule())
.overlay(Capsule().strokeBorder(.white, lineWidth: 1)
)
VStack(alignment: .leading) {
Text(crewMember.astronaut.name)
.foregroundColor(.white)
.font(.headline)
Text(crewMember.role)
.foregroundColor(.secondary)
}
}
.padding(.horizontal)
}
}
}
}
}
.padding(.bottom)
}
}
.navigationTitle(mission.displayName)
navigationBarTitleDisplayMode(.inline)
background(.darkBackground)
}
}
struct MissionView_Previews: PreviewProvider {
static let missions : [Mission] = Bundle.main.decode("missions.json")
static let astronauts : [String : Astronaut] = Bundle.main.decode("astronauts.json")
static var previews: some View {
MissionView(mission: missions[0], astronauts: astronauts)
.preferredColorScheme(.dark)
}
}
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 load \(file) from bundle.")
}
return loaded
}
}
Not putting Mission, Astronaut, and Color-Theme here since they are simple code.
Appreciate anything.
Will try run the simulator again after all modules on Project 8 is finished and see if I run into the same problem again.