메인 화면에서 각 미션을 클릭하면 볼 수 있는 MissionView를 만들었다.
struct MissionView: View {
let mission: Mission
var body: some View {
ScrollView {
VStack {
Image(mission.image)
.resizable()
.scaledToFit()
.containerRelativeFrame(.horizontal) { width, axis in
width * 0.6
}
VStack(alignment: .leading, spacing: 10) {
Text(mission.displayName)
.font(.largeTitle.bold())
Text(mission.description)
}
.padding()
}
}
.navigationTitle(mission.displayName)
.navigationBarTitleDisplayMode(.inline)
.background(.darkBackground)
}
}
이 중 짚을 점은, NavigationTitle을 뒤로 가기 버튼과 동일한 선상에 작은 글씨로 넣을 수 있다.
.navigationBarTitleDisplayMode(.inline)
그리고 미리보기(Preview)할 때 미션을 불러와서 상수에 저장하고 이 불러온 값을 입력했다. 이때 2줄 이상의 코드를 만드므로 return을 필수로 작성해야 한다.
#Preview {
let missions: [Mission] = Bundle.main.decode("missions.json")
return MissionView(mission: missions[0])
.preferredColorScheme(.dark)
}
❗️ 그렇지 않을 경우 Ambiguous use of 'init(_:traits:body)' 에러를 만나게 된다!
MissionView에서는 해당 프로젝트의 참여자를 보여준다. 그리고 이 참여자의 정보를 클릭하면 참여자의 상세 정보로 넘어간다.
이를 구현하기 위해서는 Mission 모델에 참여자들을 Astronaut을 CrewMember라는 모델로 crew에 저장하면 된다. 그리고 crewMember를 설정하기 위해 MissionView의 initializer를 설정하면 된다.
❗️ 혹시라도 없거나 누락된 정보를 가리키는 일부 JSON을 프로젝트에 포함하면 안되기 때문에 fatalError로 runtime 이전에 종료되도록 설정해야 한다.
struct MissionView: View {
struct CrewMember {
let role: String
let astronaut: Astronaut
}
let mission: Mission
let crew: [CrewMember]
var body: some View {
// ...
}
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)")
}
}
}
}