Wrapping the feature up

All of the code are in place; you understand multithreading and how callbacks can be used in a multithread environment. You saw the defer statement and how it can be used to execute a block of code at the end of a scope. Yet, if you build and run your app and add a new movie, the rating isn't actually displayed.

The following are the three reasons why this is happening:

  • We aren't setting the movie's rating on the table view cell
  • The network request doesn't succeed due to App Transport Security
  • We're not observing the update

We'll solve these issues in order, starting with the table view cell.

Adding the rating to the movie cell

Currently, the movie table view displays cells just have a title. UITableViewCell has a built-in option to display a title and a subtitle for a cell. Open the Main.storyboard and select the prototype cell for the movies. In the Attributes Inspector field, change the cell's style from basic to subtitle. This will enable us to use the detailTextLabel on our table view cell. This is where we'll display the movie rating.

In MoviesViewController, add the following line to tableView(_:cellForRow:AtIndexPath:), right after you set the cell's title:

cell.detailTextLabel?.text = "Rating: (movie.popularity)" 

This line will put the movie's popularity rating in a string and assign it as text for the detail text label.

If you build and run your app now, all movies should have a popularity of 0.0. Let's fix this by resolving our networking issue.

Understanding App Transport Security

With iOS 9, Apple introduced App Transport Security (ATS). ATS is intended to make applications safer and more secure by prohibiting the use of non-HTTPS resources. This is a great security feature, as it protects your users from a wide range of attacks that can be executed on regular HTTP connections.

If you paid close attention to the URL we were using to fetch movies, you should have noticed that we attempted to use an HTTPS resource, so we should be fine. However, our network requests are still blocked by ATS, why is this?

Well, Apple has pretty strict requirements. At the time of writing this book, the movie database used SHA-1 signing of their certificates, whereas Apple required SHA-2. Because of this, we will need to circumvent ATS for now. Our users should be safe regardless since the movie database supports HTTPS, just not the version Apple considers to be secure enough.

To do this, open the Info.plist file and add a new dictionary key named App Transport Security Settings. In this dictionary, you will need an Exception Domains dictionary. Add a new dictionary key named themoviedb.org to this dictionary and add two Booleans to this dictionary. Both should have YES as their values, and they should be named NSIncludesSubdomains and NSTemporaryExceptionAllowsInsecureHTTPLoads. Refer to the following screenshot to make sure that you've set this up correctly:

Understanding App Transport Security

If you add a new movie to a family member now, nothing updates yet. However, if you go back to the family overview and then back to the family member, you'll see that the rating for the most recent movie is updated. Great, now all we need to do is make sure that we observe the managed object context for updates to the movies so we can reload them if their rating changes.

Observing changes to movie ratings

We're already observing the managed object context for changes but we're only processing them if the family member we're looking at has updated. We should replace this logic so it will reload the table view if either the family member or their favorite movies change.

Update the managedObjectContextDidChange(_:) method as follows:

func managedObjectContextDidChange(notification: NSNotification) { 
    guard let userInfo = notification.userInfo 
        else { return } 
     
    if let updatedObjects = userInfo[NSUpdatedObjectsKey] 
      as? Set<FamilyMember>, 
        let familyMember = self.familyMember, 
          updatedObjects.contains(familyMember) { 
         
        tableView.reloadData() 
    } 
 
    if let updatedObjects = userInfo[NSUpdatedObjectsKey] 
      as? Set<Movie> { 
        for object in updatedObjects { 
            if object.familyMember == familyMember { 
                tableView.reloadData() 
                break 
            } 
        } 
    } 
}  

Note

The logic for observing the family member hasn't changed; its conditions simply moved from the guard statement to an if statement. Another if statement was also added for the movies. If the updated object set is a list of movies, we loop through the movies and check whether one of the movies has the current family member as its family member. If so, we refresh the table immediately and break out of the loop.

It's important that we set the loop up like this because we could have just added a movie for family member A and then switched to family member B while the new movie for family member A was still loading its rating. Also, breaking out of the loop early ensures that we won't loop over way more objects than needed. All we want to do is refresh the table view if one of the current family member's favorite movies are updated.

Okay, build and run your app to take it for a spin! You'll notice that everything works as you'd want to right now. Adding new movies triggers a network request; as soon as it finishes, the UI is updated with the new rating. Sometimes, this update will be over in an instant while it could take a short while if you have a slow Internet connection. Great! That's it for this feature.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.178.157