Passing data between view controllers

The final frontier for the HelloContacts app is to display some actual information about a selected contact. In order to do this, we'll need to add some new outlets to the ContactDetailViewController. The data that's loaded for contacts also needs to be expanded a little bit so a contact's phone number, e-mail address, and postal address are fetched. Finally, the contact data needs to be passed from the overview to the detail page so the detail page is able to actually display the data. The steps we'll take are as follows:

  1. Updating the data loading and model.
  2. Passing the model to the detail page.
  3. Implementing new outlets and display data.

Updating the data loading and model

Currently, the code in ViewController.swift specifies that just the given name, family name, image data, and image availability should be fetched. We need to expand this so the e-mail address, postal address, and phone number are fetched as well. Update the retrieveContacts(store:) method with the following code:

let keysToFetch = [CNContactGivenNameKey, 
                   CNContactFamilyNameKey, 
                   CNContactImageDataKey, 
                   CNContactImageDataAvailableKey, 
                   CNContactEmailAddressesKey,

                   CNContactPhoneNumbersKey,

                   CNContactPostalAddressesKey]

The new keys are highlighted so you can easily see what has changed.

Previously, you added some computed variables to the HCContact class so you can easily access certain properties of the CNContact class. We'll do the same for the news keys. Add the following code in HCContact.swift:

var emailAddress: String { 
    return String(contact.emailAddresses.first?.value ?? "--") 
} 
 
var phoneNumber: String { 
    return String(contact.phoneNumbers.first?.value.stringValue ?? "--") 
} 
 
var address: String { 
    let street = String(contact.postalAddresses.first?.value.street ?? "--") 
    let city = String(contact.postalAddresses.first?.value.city ?? "--") 
    return "(street), (city)" 
} 

If you examine this code closely, you'll notice that the phoneNumber and address variables aren't as straight forward as the others. That's because the corresponding properties on CNContact are arrays of NSValue objects. Since we're only interested in the first item available, we use the first property that's defined on the array. When available, it returns the first element in the array. Then, the value property is used to extract the actual string value. The nil coalescing operator (??) is then used to return either the retrieved value or a placeholder string. If the retrieved value doesn't exist, the placeholder is used instead.

For the postal address, the code is more complex. A postal address has multiple fields so we extract street and city with the same technique that's used for the phone number. Then, a string is returned with both values separated with a comma.

Now that we have exposed the new properties to users of the HCContact class, it's time to pass it on to the detail page.

Passing the model to the detail page

The transition from the overview page to the detail page is implemented with a segue. The segue is triggered whenever a user has selected a contact, and it takes care of getting the detail page on screen. As we're using a segue, there is a dedicated point that we can use to pass data from the overview to the detail page. This point is a method called prepare(for:sender:). This method is called whenever a segue is about to happen and it allows you to access the destination. Let's implement it right now to see how it enables you to pass the selected contact to the detail page:

override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) { 
     (where keyword is replaced by a ,)
    if let contactDetailVC = segue.destination as? ContactDetailViewController 
        where segue.identifier == "contactDetailSegue", 
        let selectedIndex = collectionView.indexPathsForSelectedItems()?.first { 
 
        contactDetailVC.contact = contacts[selectedIndex.row] 
    } 
} 

This implementation first verifies that the destination is of the correct type. Then, it also makes sure that the segue's identifier matches the identifier we set up for this segue. Finally, the first (and only) selected index path is read from the collection view. This information is then used to assign the contact from the contacts array to a contact property on the instance of ContactDetailViewController we're transitioning to. This property does not exist yet, but we'll implement it momentarily. This method is everything required to pass data from the overview to the detail page.

Implementing new outlets and display data

Using the data that's received on the detail page is pretty straightforward. We need to add some @IBOutlets and a contact property. Then, we will use the information available in the contact at an appropriate time to show it to the user. Finally, the created outlets should be hooked up through the Interface Builder.

Let's take a look at the following required code first:

@IBOutlet var contactPhoneLabel: UILabel! 
@IBOutlet var contactEmailLabel: UILabel! 
@IBOutlet var contactAddressLabel: UILabel! 
 
var contact: HCContact? 
 
override func viewDidLoad() { 
    // current implementation... 
 
    if let contact = self.contact { 
        contact.prefetchImageIfNeeded() 
        contactImage.image = contact.contactImage 
        contactNameLabel.text = "(contact.givenName) (contact.familyName)" 
        contactPhoneLabel.text = contact.phoneNumber 
        contactEmailLabel.text = contact.emailAddress 
        contactAddressLabel.text = contact.address 
    } 
} 

This code should be added to the ContactDetailViewController.swift file. The first part declares the outlets and the contact property. The additions to viewDidLoad first check that the contact is actually set and then assigns the values to the user interface elements.

The final step is to go to the storyboard, select the detail view controller, and connect the outlets in the Connections Inspector to the user interface elements. After doing this, build and run your app to see the detail page in its full glory.

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

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