nburk
nburk

Reputation: 22731

Automatic UI updates with Apollo in Swift not working

I have the following setup for a small Apollo iOS app where I display a list of conferences in a table view and want to be able to add a conference to the list:

GraphQL:

query AllConferences {
  allConferences {
    ...ConferenceDetails
  }
}

mutation CreateConference($name: String!, $city: String!, $year: String!) {
  createConference(name: $name, city: $city, year: $year) {
    ...ConferenceDetails
  }
}

fragment ConferenceDetails on Conference {
  id
  name
  city
  year
  attendees {
    ...AttendeeDetails
  }
}

fragment AttendeeDetails on Attendee {
  id
  name
  conferences {
    id
  }
}

ConferencesTableViewController:

class ConferencesTableViewController: UITableViewController {

  var allConferencesWatcher: GraphQLQueryWatcher<AllConferencesQuery>?

  var conferences: [ConferenceDetails] = [] {
    didSet {
      tableView.reloadData()
    }
  }

  deinit {
    allConferencesWatcher?.cancel()
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    allConferencesWatcher = apollo.watch(query: AllConferencesQuery()) { result, error in
      print("Updating conferences: ", result?.data?.allConferences)
      guard let conferences = result?.data?.allConferences else {
        return
      }
      self.conferences = conferences.map { $0.fragments.conferenceDetails }
    }
  }

  // ...
  // standard implementation of UITableViewDelegate
  // ...

}

AddConferenceViewController:

class AddConferenceViewController: UIViewController {

  // ... IBOutlets

  @IBAction func saveButtonPressed() {
    let name = nameTextField.text!
    let city = cityTextField.text!
    let year = yearTextField.text!

    apollo.perform(mutation: CreateConferenceMutation(name: name, city: city, year: year)) { result, error in
      if let _ = result?.data?.createConference {
        self.presentingViewController?.dismiss(animated: true)
      }
    }

  }
}

I also implemented cacheKeyForObject in AppDelegate like so:

apollo.cacheKeyForObject = { $0["id"] }

My question is whether it is possible to benefit from automatic UI updates with this setup? Currently when the CreateConferenceMutation is performed, the table view is not updated. Am I missing something or am I hitting the limitation that is mentioned in the docs:

In some cases, just using cacheKeyFromObject is not enough for your application UI to update correctly. For example, if you want to add something to a list of objects without refetching the entire list, or if there are some objects that to which you can’t assign an object identifier, Apollo cannot automatically update existing queries for you.

Upvotes: 2

Views: 1230

Answers (1)

Martijn Walraven
Martijn Walraven

Reputation: 111

This is indeed a limitation of automatic UI updates. Although Apollo uses cacheKeyFromObject to match objects by ID, and this covers many common cases, it can't automatically update lists of objects.

In your schema, there is no way for Apollo to know that a newly added conference should be added to the allConferences list. All it knows is that allConferences returns a list of conference objects, but these could be arbitrarily selected and ordered.

So in cases like these, you will have to refetch the query from the server yourself, or change the mutation result to include the updated list.

Another option would be to manually add the new conference to the list in the client store. For this, the next version of Apollo iOS will include a manual update option similar to updateQueries in the Apollo JavaScript client.

Upvotes: 4

Related Questions