GraphQL Using the Apollo Framework: Getting Started

In this Apollo Framework for iOS tutorial, you will learn how to consume GraphQL APIs in a simple and type-safe way. By Felipe Laso-Marsetti.

4.2 (29) · 7 Reviews

Download materials
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

Displaying a List of Films

To display your films list, you’ll start by going to tableView(_:cellForRowAt:). Add the following code just before the return statement:

let film = films[indexPath.row]
cell.textLabel?.text = film.title

Here you fetch the Film for the given row. You set the label text for the cell to the film’s title. This is all pretty standard table view and cell work. :]

Build and run, and admire the list of movies you created:

Viewing Films in Jedi Archives

Sweet! You’re now fetching data, via GraphQL, and displaying it within a table view in your app. Great work!

Note: If you get a network error at this point, double-check that the port number in Apollo.swift matches the port number of the server. This is the port number returned from your yarn start command, above.

Populating the Film Details Screen

At this point, if you tap one of the film cells, the app will crash. That’s OK! You’re going to focus on this next.

Accessing Film Details Data

Again, go to FilmsViewController.swift. Replace the code in showFilmDetails(_:sender:) with the following:

guard
  let cell = sender as? UITableViewCell,
  let indexPath = tableView.indexPath(for: cell)
  else { 
    return nil
}
return FilmDetailsViewController(film: films[indexPath.row], coder: coder)

This code retrieves the index of the cell that was tapped. It returns a new FilmDetailsViewController for the specified Film. If a problem occurs and it can’t get the desired value, then it returns nil.

If you try to build now, you’ll get an error on the last sentence. This is because you previously changed the type of the film, which is now a type generated by Apollo. To fix it, go to FilmDetailsViewController.swift. At the beginning of the class, replace the film declaration with the following:

private let film: AllFilmsQuery.Data.AllFilm.Film

This is the same concept as when you created a property for your films array. This one, though, is for a single film.

Now you need to change the class initializer to accept this new type. Delete init?(film:coder) and replace it with this code:

init?(film: AllFilmsQuery.Data.AllFilm.Film, coder: NSCoder) {
  self.film = film
    
  super.init(coder: coder)
}

This new initializer receives a Film instead of a String.

Displaying Film Details

Now go to viewDidLoad() and add the following code:

title = film.title

This displays the film’s title in the navigation bar.

Next, you need to display the right number of rows, depending on the number of characters this film has. Scroll down to tableView(_:numberOfRowsInSection:). Replace the line that reads return 0 with the following:

return film.characterConnection?.characters?.count ?? 0

Here you return the number of characters associated with the current film. Notice how you access the characters count. The count comes from the characters array in the Film‘s characterConnection. Since characters is optional, you must allow for the case where there are no characters. If this happens, you return zero.

Now you’re ready for the last step. You need to display the movie information in the table’s cells. Go to tableView(_:cellForRowAt:) and locate this block of code:

if indexPath.row == 0 {
  cell.textLabel?.text = "Episode"
} else if indexPath.row == 1 {
  cell.textLabel?.text = "Released"
} else if indexPath.row == 2 {
  cell.textLabel?.text = "Director"
}

Replace it with this:

if indexPath.row == 0 {
  cell.textLabel?.text = "Episode"  
  if let episodeNumber = film.episodeId {
    cell.detailTextLabel?.text = "\(episodeNumber)"
  }
} else if indexPath.row == 1 {
  cell.textLabel?.text = "Released"
  cell.detailTextLabel?.text = film.releaseDate
} else if indexPath.row == 2 {
  cell.textLabel?.text = "Director"
  cell.detailTextLabel?.text = film.director
}

This code retrieves the film’s episode number, release date and director. It then assigns the information to the text fields of the appropriate cells based on the row number.

Now build and run, and tap one of the films.

Showing The Right Number of Cells For Characters

Great! You’re displaying the film details!

But, if you look closely, the characters list is just a bunch of repeated cells. The good news is that you’re showing the correct number of cells for the characters in this film. But now you need to update the code to display the characters’ names.

Displaying the Characters List

Again, go to tableView(_:cellForRowAt:) Add the following code just before the last return statement of the method:

cell.textLabel?.text = film.characterConnection?.characters?[indexPath.row]?.name

This sets the name of the character in the cell’s text field.

Build and run one more time, and check out the results:

Showing The Character Names In The List

Yay! The characters list is looking much, much better. :]

Lovely Looking List

Populating the Character Details Screen

Earlier you found that tapping a film cell caused the app to crash. Now, tapping a character cell will now crash your app! And as you did for the film details, you’ll correct this by passing along the character to the character details screen.

Accessing Character Details Data

Go back to FilmDetailsViewController.swift. Replace the code in showCharacterDetails(_:sender:) with the following:

guard 
  let cell = sender as? UITableViewCell,
  let indexPath = tableView.indexPath(for: cell),
  let character = film.characterConnection?.characters?[indexPath.row] 
  else {    
    return nil
}
   
return CharacterDetailsViewController(character: character, coder: coder)

Here you retrieve the index of the selected row. You use it to initialize CharacterDetailsViewController with the selected character.

If you try to build now, you’ll see an error because the character’s type has changed. To fix it, open CharacterDetailsViewController.swift. Inside the class implementation, replace the line declaring character with the following:

let character: AllFilmsQuery.Data.AllFilm.Film.CharacterConnection.Character

This will look very familiar to you. It’s similar to what you did for an array of films, and for a single film. Here you create a property of type Character. You’ll use this property to populate the character details screen.

And, as you saw before, an error occurs. This is because the initializer expects a different type for the character.

Delete init?(character:coder:) and replace it with the following:

init?(
  character: AllFilmsQuery.Data.AllFilm.Film.CharacterConnection.Character, 
  coder: NSCoder
) {
  self.character = character
    
  super.init(coder: coder)
}

This initializer uses the new Character type and sets the value of character.

Almost There!

Displaying Character Details

Now, go to viewDidLoad() and add the following code at the end:

title = character.name

This displays the name of the character in the navigation bar.

Next, go to tableView(_:cellForRowAt:). Replace the existing block of if and else if statements with the following:

if indexPath.row == 0 {
  cell.textLabel?.text = "Birth Year"
  cell.detailTextLabel?.text = character.birthYear
} else if indexPath.row == 1 {
  cell.textLabel?.text = "Eye Color"
  cell.detailTextLabel?.text = character.eyeColor
} else if indexPath.row == 2 {
  cell.textLabel?.text = "Hair Color"
  cell.detailTextLabel?.text = character.hairColor
} else if indexPath.row == 3 {
  cell.textLabel?.text = "Home Planet"
  cell.detailTextLabel?.text = character.homeworld?.name
}

This code inserts the appropriate text into each cell, using the row number to populate the cells correctly.

Your code is now complete! Woohoo!

Build and run. Check out the results by navigating to a film’s detail screen and then selecting a character. You’ll now see the character’s information in the screen.

Showing a Character's Details

Awesome work completing the tutorial! Congratulations!

Swift Yay!