Overview
Time to bring live data into our UI.
In this lesson, we will:
- Configure the
LaunchListViewModelto display a list of launches - Loop through the launches and build the app
Configure LaunchListViewModel
First up, we'll display a list of Launches using a List.
In LaunchListViewModel add a new variable to hold the launches returned by the query:
@Published var launches = [LaunchListQuery.Data.Launches.Launch]()@Published var appAlert: AppAlert?@Published var notificationMessage: String?
Next, scroll down until you locate the loadMoreLaunches() method. Here, we'll replace the TODO with the code to run the LaunchListQuery:
func loadMoreLaunches() {Network.shared.apollo.fetch(query: LaunchListQuery()) { [weak self] result inguard let self = self else {return}switch result {case .success(let graphQLResult):if let launchConnection = graphQLResult.data?.launches {self.launches.append(contentsOf: launchConnection.launches.compactMap({ $0 }))}if let errors = graphQLResult.errors {self.appAlert = .errors(errors: errors)}case .failure(let error):self.appAlert = .errors(errors: [error])}}}
GraphQLResult has both a data property and an errors property. This is because GraphQL allows partial data to be returned if it's non-null.
In the example we're working with now, we could theoretically obtain a list of launches, and then an error stating that a launch with a particular ID could not be retrieved.
This is why when you get a GraphQLResult, you generally want to check both the data property (to display any results you got from the server) and the errors property (to try to handle any errors you received from the server).
As you can see in the code, the sample project has already provided an easy way to display error alerts by simply assigning the desired value to the appAlert property.
Use Launches in the UI
First let's update our LaunchRow view to be able to display the data for a specific Launch. Open up LaunchRow and at the top of the file add import RocketReserverAPI and then add the following variable:
import SwiftUIimport RocketReserverAPIstruct LaunchRow: View {let launch: LaunchListQuery.Data.Launches.Launchprivate let placeholderImg = Image("placeholder")// ... additional properties}
Then let's update one of our Text views to show the launch site:
VStack(alignment: .leading) {Text("Mission Name")Text(launch.site ?? "Launch Site").font(.system(size: 14))}
Now that our LaunchRow is updated, let's move over to LaunchListView and start displaying our Launches in the list.
Update the ForEach loop to loop through every launch item from our viewModel and create a LaunchRow for it:
List {ForEach(0..<viewModel.launches.count, id: \.self) { index inLaunchRow(launch: viewModel.launches[index])}}
The last step is to call the loadMoreLaunches method we updated earlier to actually query the server for data. To do this update the TODO in the .task { } in LaunchListView to the following:
.task {viewModel.loadMoreLaunches()}
Test your query
Build and run the application—you now have a UI connected to your GraphQL queries! 🚀
Practice
data property and the errors property in a GraphQLResult? Select all that apply.Up next
Showing our basic launch details is only the beginning. Next up, let's supplement our query with a few more fields.
Share your questions and comments about this lesson
This course is currently in
You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.