To update our movie, we will implement the final step of the approach that was outlined earlier. We 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, at approximately line 40 (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 our view controller. We can simply use the helper and provide it a movie to fetch the rating for with a callback and we'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. We need to do this 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 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 well enough. 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 like we've done before, but in this case, we're simply making our problem bigger. 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 we have looked at all the code involved, let's see what all this threading talk means in a more visual way.