Join John Nastos for an in-depth discussion in this video Understanding the master/detail view controllers, part of Building an iOS Address Book App.
- [Voiceover] In the Creating a New Project Video, I mentioned that we would be creating a master/detail application. Let's dig into what a master/detail application is and how it works. A master/detail application is a very common paradigm in iOS. It has a list of items in a table, and each item can be tapped to reveal more information. Depending on what size of device you view the application on, this could have a different appearance. The content on each device is displayed using a split view controller. You can find more information on this in the iOS Developer Library on Apple.com The default mail app in iOS is a great example of this type of application.
On the iPhone, the master view shows a list of messages. Then, when a message is tapped, it reveals the detail view, which shows the message itself. If you look at the same application on an iPad, though, the interface changes quite a bit. Now, because there's more space available for the interface, both the master table and the detail view can be shown at the same time. Let's see what happens using Apple's master detail template. So I'll go back to Xcode, and I'll take a look at the template that was created when I made the application.
Apple's template provides a fair amount of built in functionality that you should understand in detail so that when it comes time to start editing the template to add functionality to the app that we're building, you understand what it's built on and what you're changing. First, without changing anything, I'm going to run the project in the simulator to see what happens. The app launches, and it shows a fairly empty screen with Edit and Add buttons in the navigation bar.
If I press the Add button, a new item gets added to the table with the current time and date stamp. If I tap that item, it shows me Detail View with a label showing the same time stamp. Then, I can navigate back to the original controller and tap the Edit button. That button reveals an option to delete the item that I just created. In order to understand how this is all working, let's go back into Xcode and examine the files that were generated by the template.
First, let's check out the Main.storyboard file. On the left of the storyboard, you can see that everything originates from a split view controller. That split view controller is set to be the initial controller on the storyboard, meaning that it will be loaded as the main screen. Then, on the top row of controllers, there's a navigation controller, and below it, it has a UITableViewController as its root view controller. This is the view controller that represents the master table of data, the same one that the time stamp item got added to when I ran the app in the simulator a moment ago.
Along the bottom row, there's another navigation controller followed by the detail view controller. You might notice that there's also a connection between the master view controller table and the detail view navigation controller. If I click on it, you can see that it connects the cell from the master view table to the detail navigation controller. This means that when a cell is tapped on the master table, it will reveal the detail controller. Now that we've looked at the storyboard, let's take a look at how the template implemented this in code.
First, let's look at the master view controller. At the top, it has variables to represent the detail view controller, plus an array where the objects are stored that appear in the table. In the viewDidLoad method, a couple very important things happen. You may have noticed that in the simulator, there were Edit and Add buttons at the top of the screen, but these buttons didn't show up in the storyboard. That's because they get added here, in the viewDidLoad method. Then, a few lines lower, there's code to get reference to the detail view controller.
When the Add button was created, you can see that it is going to call a method called insertNewObject and that you can find on this selector here. If I go down to that method, I can see that when the method is called, a new NSDate object is created and added to the objects array in the first position, atIndex: 0 Then, a corresponding item gets added to the table view. You can see that where it says self.tableView.insertRowsAtIndexPaths And then it uses an array of the index path which it created above at row zero in section zero.
Next, let's look at the prepareForSegue method. This gets called whenever a storyboard segue is initiated from this view controller. If you remember, when we looked at the storyboard file, the table cells in the master view controller were hooked up via a segue to the detail view controller. If I click on that segue, I can see that the segue has an identifier named showDetail Back in the code for the view controller, there's an if statement to test to see that it is indeed the segue that is happening, if segue.identifier = "showDetail" If it is, it retrieves the element from the objects array that corresponds to the cell that was tapped.
Then, it gets a reference to the detail view controller that the segue is pointing towards and sets that object as the detailItem variable on that view controller. That line is controller.detailItem = object Don't worry too much about the specifics of what's going on here for now. I'm just doing a brief overview of the default template, and when we start editing to create our own address book app, I'll be more detailed with what each line of code does. The next section of this file details the table view and how the information in the table is populated.
First, there's a method that tells the system how many sections the table view has, just one at the moment. Then, within each section, the system needs to know how many items there are. In this case, that's the length of the objects array. So you can see in TableView, numberOfRowsInSection it returns objects.count When it comes time to display a cell on the screen, the system calls TableView, cellForRowAtIndexPath The first line of this method gets a reference to the cell using the dequeueReusableCellWithIdentifier method on the table view.
You'll notice that it asks for a cell with the identifier "Cell" If I go back to the storyboard and click on a cell in the table, you'll see that the cell here has that same identifier. So back in the code, this means that the method will get a copy of this type of cell, and then modify it to display the correct information. Next, the method gets a reference to the correct object by getting the item in the object array at the index passed into the method. That line is let object = objects which is the array, at the position indexPath.row And finally, it sets the cell's label to the description of that object.
Later on, we'll be editing this method so that the cell displays our contact's name. That's followed up by a method that gets called by the system to see if the row can be edited. In this case, it's always true. This tells the system that the row can be deleted. And finally, a method that gets called if the row is deleted. This method is TableView, commitEditingStyle In this case, the corresponding object is removed from the object array and the row is deleted from the table. Before we move on, let's take just a quick look at the detail view controller.
The first thing we see in this file is a variable called detailDescriptionLabel You'll notice that it has a special token beside it called @IBOutlet This tells Xcode that this variable should be connected to an element in the storyboard. And, if we go back to the storyboard, we can see that the label on the view controller is in fact connected to that variable. Back in the code, there's another variable called detailItem This one has an interesting piece of Swift code attached to it.
It's set up so that when the value of this variable gets set, this block of code gets called, and in this case, it in turn calls the configureView method. Inside the configureView method, the code first makes sure that self.detailItem is not nil by using an if let statement. Then, it sets the text of the label that was defined with the IBOutlet above to the description of that detail object.
Build the project step-by-step and then use what you've learned to explore your own app ideas.
- Creating the project in Xcode
- Using Auto Layout to design the UI
- Attaching the interface to the code
- Creating the data model, including a Person class
- Adding stored data to the UI
- Displaying a contact's address with MapKit
- Linking contact info to other iOS apps
- Adding persistence
- Working with table views
- Writing tests
- Preparing to publish the app in the App Store