Updating a movie with a popularity rating

To update the movie object, you will implement the final step of the approach that was outlined earlier. You need to asynchronously fetch a rating from the movie database and then use that rating to update the movie. The following code should be added to MoviesViewController.swift, right after adding a new movie to a family member, inside of the persist block, approximately at line 35 (depending on how you have formatted your code):

let helper = MovieDBHelper()
helper.fetchRating(forMovie: name) { rating in
  guard let rating = rating
    else { return }

  moc.persist {
    movie.popularity = rating
  }
} 

You can see that the helper abstraction provides a nice interface for the view controller. You can simply use the helper and provide it a movie to fetch the rating for with a callback and you're all set. Abstracting code like this can make maintaining your code a lot more fun in the long run.

The most surprising thing in the preceding snippet is that moc.persist is called again inside of the helper callback. This must be done because this callback is actually executed long after the initial persist has finished. Actually, this callback isn't even executed on the same thread as the code it's surrounded by.

To see how your code fails if you don't properly persist your model, try replacing the moc.persist block in the rating retrieval callback with the following code:

movie.popularity = rating  
do {  
  try moc.save()  
} catch {  
  moc.rollback()  
}

If you add a new movie now, the rating will still be fetched. However, you will suddenly run into issues when reloading your table view. This is because the managed object context was saved on a background thread. This means that the notification that informs the table view about updates is also sent on a background thread. You could resolve the issue by pushing the reloadData() call onto the main thread as you've done before, but in this case, doing so would only make the problem worse. Your app might work fine for a while, but once your app grows in complexity, using the same managed object context in multiple threads will most certainly cause crashes. Therefore, it's important to always make sure that you access managed objects and their contexts on the correct thread by using a construct, such as the persist method we implemented for this app.

Now that you have looked at all the code involved, let's see what all this threading talk means in a more visual way.