Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2009-410
$eventId
ID of event: wwdc2009
$eventContentId
ID of session without event part: 410
$eventShortId
Shortened ID of event: wwdc09
$year
Year of session: 2009
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2009] [Session 410] iPhone Appl...

WWDC09 • Session 410

iPhone Application Design Using Interface Builder

iPhone • 1:00:01

Interface Builder provides the easiest route to an elegant and well-designed iPhone application, letting you seamlessly implement many popular interface styles. Take your experience with Interface Builder to the next level and learn how to efficiently build and structure your iPhone interface. Find out how to create a multi-screen interface, work with view controllers, employ navigation controllers, and properly isolate data across master-detail interface pairs.

Speakers: Rob Marini, Matt Gamble

Unlisted on Apple Developer site

Downloads from Apple

SD Video (254.7 MB)

Transcript

This transcript has potential transcription errors. We are working on an improved version.

iPhone Application Design Using Interface Builder. My name is Rob Marini. I'm an engineer on the Interface Builder team and I'll be joined later today by one of my colleagues, Matt Gamble. Today we're here to talk about applications and if you look at the whole gamut of applications that are available on the iPhone, you can basically boil them down into three distinct types of apps.

The first of which are Single Screen applications. We also have Hierarchical applications and Tab-based applications. Today I'll be talking to you about Single Screen applications, but before we do that, we need to talk about some basics involved in iPhone application design. More specifically, we have to talk about View Controllers. View Controller are fundamental to iPhone app development.

They're responsible for the management of a Single View or a view hierarchy, and as a developer, your job is to provide a View Controller with its view. You can do that either through the Load View mechanism or more commonly and more simply, by using an Interface Builder document.

The other great thing about View Controllers is that they make your life much easier in dealing with memory management. They respond to these things called memory warnings, so that if you're running in a situation where you have a lot of things going on on the system, you can let go of some of the things that you don't need so that you can ensure that your application keeps running smoothly.

If we look at the Maps application that I showed you earlier, you can see that there is this single screen that's managed by a View Controller, and it essentially loads this view onto the screen that might come from an Interface Builder document. And very commonly, there is a one-to-one mapping between view Controllers and Interface Builder documents and this pattern is very powerful because it allows you to run as performant as possible and to ensure that things like lazy loading and unloading are available to you.

There are two ways to create View Controllers. One is what we call an on-demand View Controller, and these are typically done in code and they're really flexible. You can create them in response to user actions. And the nice thing about that is that you don't need to know ahead of time if you're actually going to need them. And later today, Matt Gamble will be talking in great detail about that. The other way to create a View Controller is in Interface Builder, and we call that a Static View Controller. These are useful for your initial View Controllers.

You typically see them inside of your Main Window, Interface Builder document, and the nice thing about them obviously is that you don't need to write code. Going back to the Maps app, if we break it down, we can see that it has two Interface Builder documents. The first of which is this Main Window, Interface Builder File; and looking at that document contents, we can see that there is this View Controller.

This is one of the Static View Controllers that we talked about earlier. And by putting it inside of our IB document, we A, know that it shares the life of our window which is the life of the whole application and we don't actually need to write this in code.

If we open that up, we can see that it loads its view from another Interface Builder file. This maps View Controller. So if we look at that, the first thing that you probably noticed is this thing called File Zoner; and File Zoner is really a reference that allows you to link to the thing that manages the view.

It doesn't actually exist inside of your Interface Builder document, it exists somewhere else. And File Zoner is typically where you would put the things that are going to manage the view contents that are being presented as part of your Interface Builder document. And perhaps most importantly, there's usually an outlet going from File Zoner to your view contents of the IB document and that lets the View Controller know that that is the thing that it should be presenting on screen. If we look at the view file, you can see that we have the Interface Builder representation of our Maps application.

We have a Search bar, a Mapview, and a Toolbar with some buttons. You might be wondering at this point, why do we have two interface builder documents? We only have a single screen of content. And the reason goes back to something that I mentioned earlier, which was lazy loading and unloading.

For a single screen of content, this might not be particularly useful, but after you put your app on the store and sell a few million copies, you might want to add features to it and at that point, this is great. It also enables refactorability, which is something that we'll be taking advantage of later on by means of these clean separations between the things that really are your application and the things that are essentially every application.

Today we're going to be building applications. We're going to be building one application, three different ways, starting with a Single Screen variant. And their application is a to-do list. So this Single Screen version, it's the details of a single task. Later we'll expand upon that and have a list of tasks and the details that go with them. This is a hierarchical application and then we'll expand upon that, and present different views of our data by using a Tab Bar Controller. So right now, I'm going to show you how to build a Single Screen application.

So, here I have the lovely new Start Up screen for Xcode on Snow Leopard and I'm going to create a new project. Now I could create a View-based application and get a lot of the things that I'm going to do right now for free, but I'm going to start with a Window-based application, just so I can show you everything that goes in to one of our templates as well. So, I'll create that. I'm going to save it on the Desktop.

Name it "To-Do" and here we go. (Make that a little bigger.) We can see here that we have our app delegate and our Main Window zip and this is a very bare bones project as I mentioned. So I'm going to cheat a bit and drag in some resources. The first thing that I'm going to need are some images and a property list, which I'll explain in just a second.

Drag these in and add them to our project. So the property list is essentially just some storage that I've used to predefine some tasks. You don't have to watch me type them in. Background image, a garbage can for maybe one of our chores and a check mark. I also have some code that I previously wrote.

Drag that in as well. Say Yes, add them. And here we have a model and a controller. I'm going to take a look at the model right now very briefly. It's just a task, has an image, a title, summary and a state saying whether it's complete. There's this TD Task Vendor Class and this is essentially just a helper class that I wrote that will go through our property list of tasks and return it to our project as an array.

Really straightforward. Let's take a look at the View Controller. So right away, you can see that I have a task and I have some IB outlets and the View Controller's job in this case is essentially to take the contents of the task and allow me to represent them on screen. It's acting as the intermediary between our Interface Builder document and our model.

Take a look at the implementation file. Here you can see I have some memory management code, just releasing them when the controller gets de-alloced and synthesizing the properties. And the two probably most interesting methods are View Did Load and View Did Unload. The View Did Load gets called when my view is actually displayed, just before the view is displayed on the screen really, and here all I'm doing is setting the images, the text and the check button inside of the task on screen to be representative of their state in our model.

And I also have this View Did Unload method, which is new in iPhone 3.0 and it's called when the view is no longer relevant to what's being displayed on the screen and so we just clear things up in there and give the rest of our applications some more memory.

And I also have an IB action method here and just as a reminder, by saying something is an IB action, you're telling Interface Builder that this is something that you might want to be using there, for instance, when I touch a button, and that's exactly what I'm using it for.

It's called Change Task State, and this is what allows us to check and uncheck the done status of our task. So now, I'm going to go ahead and add a new file and I'm going to create a user interface file. I'm going to do a View ZIP, go ahead, and call that TDDetailViewController.

It's a lot harder spelling on stage than it looks. I'm going to open that up in Interface Builder. Here we go. So, here you can see I have my document window and my design surface. So I'm going to start by dragging in an image view, because I know I have that background image that I want to use.

So I'll add that here and in the identity inspect, or rather in the attributes inspector, I'm just going to go ahead and pick an image from our project, the To-Do background. There. And I'm also going to change the view's drawing mode to be Top and what this will allow us to do is you can see we have a lot of detail on the top of our image and not a lot on the bottom. So in the case that where perhaps get a phone call and go back to our application, we get that green bar on the top.

Right now, we could actually just push the view down a little. But I had some more things that I needed to add, so I'm going to go ahead and do those now. Needed a button, so I'm going to drag that in here and we'll just put that there.

Now I'm going to change this from being a rounded rectangle to make a custom button and I'm going to change the Selected State, have a background image of the check mark. OK. Now I'm going to add another image view, because remember I had that picture of the lovely garbage can.

I'm going to stick that kind of here, resize it a little, and I know that I need it to be 64x64 and I could fiddle with this for a while or I could go to the Size Inspector and I'll give you a brief tour of this. Here you can see we have the Size and Position section. So I want to pin it to the top left and resize it from there and I know it has to be 64x64. Hit Enter and I resized it.

And now I'll manually move that over with the keyboard about there. Now I had a title and the thing that probably is best for a title is a Label. So I'm going to drag one out, put it here and I am going to make it the width of our text area in our image. And I also had a summary.

So I'm going to go ahead and drag in a Text View for that. Maybe stick that about there and resize that as well. So there, we've just built our interface. Now we actually want it to do something and for that we're going to go to File Zoner and the important thing here is as I mentioned earlier, File Zoner is a link in this case, to the View Controller that actually has the outlets in action. So we need to let Interface Builder know what File Zoner is in this case.

And if you would use the View Based Application Template, this would have been set up for you. So I'm going to go to the Identity Inspector and change the class of File Zoner to be TD Detail View Controller and now I'm going to wire it up. Oh, and in Xcode I actually added these into these files. So I'm just going to stick those into classes, very quickly.

[ No speaking ]

It's never a demo unless you do something wrong. OK. So now if I look at the outlets in HUD, I can see that I have a list of all of my outlooks and actions, so I'm just going to go ahead and drag from our outlets to what they need to be connected to on screen. So Complete Task button, well I'm going to add that to the button.

And you might notice that like I can drag this over the image and it won't actually offer it or allow me to connect it, because it knows that it wants a button. So go ahead and connect it to the button, connect that to the Image View. There's this Search Display Controller, which I'm not going to connect now but Matt will be talking about later.

We have a Summary Text view, a Title Label, and extremely important here is this view. So I'm going to connect that to our view and this is of course telling the View Controller that this is the thing that it needs to present to the user when the Interface Builder document loads. And I also have to connect an action to this button.

So I'll just go ahead and do that and set it to Change Task state. There. I'm going to Save this, go back to Xcode and at this point I'm going to go to the Application Delegate, because there are some things I need to do here to let it know about our initial View Controller. So first I need to actually create an instance variable for the View Controller. There. And now I need to create a property for it and send it as an IB outlet so that I can reference it in Interface Builder. Save that.

Go to the Implementation file and there are some things I need to import. I'm just going to replace this synthesize because I have my own and there are these two methods, Application Did Finish Launching and DeAlloc. I'm going to go ahead and replace those as well and I'll give you a brief tour of this.

I'm creating a vendor, getting the tasks from the property list, adding, creating a task from one of the tasks in the property list, setting them to be the task that I create to be the task of my View Controller, setting my View Controller's view to be a sub-view of my window, and then doing some memory management. It's very straightforward.

I'll save this file and I'm going to go ahead and Build and Run. And I typed something wrong. "TD" there. OK. Now I'm going to go ahead and Build and Run. And as you can see, we see nothing. Well why do we see nothing? Remember that I mentioned earlier that there were two files in the Maps. Well we only worked with one here, so now we're going to look at the other one, which is this Main Window file.

So I'm going to double-click to launch that in IB and I'm going to hide Xcode for now and hide the simulator. If you look in the contents here, you can see that we have a window which funnily enough, looks like what we saw in the simulator and we have our App Delegate. Remember that I mentioned before that there were these Static View Controllers? Well this is the perfect place for one because I know that it's going to exist for the lifetime of my application, which is the lifetime of the window.

So I'm going to add one here and it's important to know here that we don't want the class to be a UI View Controller, we want it to be our TD Detail View Controller because this is actually where our TD Detail View Controller will be initialized. So I'm going to hit Enter and that lets Interface Builder know that when it comes time to create this View Controller, that's the class that it should be using.

And I had an outlet in the App Delegate for the View Controller, so I'm going to Control Click there and I have this initial View Controller, I'll drag that there and it's important to remember that we have our interface in a separate Interface Builder file so we need to let the View Controller know that it should be loading the view from that file.

So I'll go to the Attributes Inspector here and there's a field called Nib Name, so I'll set that to be the name of the nib, which was TD Detail View Controller; and Interface Builder communicates very seamlessly with Xcode so it knows what the files are already. It hopefully auto-completed it for me. So hit Enter to save this. Go back to Xcode and now I will Run.

And now you can see our interface. Working check box, et cetera. And this is displaying the contents from that first task of our property list, on the screen, in the interface that we designed. OK. That was our demo of building a Single Screen application. What did we just talk about? Well, the first thing to remember is that a View Controller is responsible for a Single View or a Single View Hierarchy. And so that's something that you typically provide to the View Controller, inside of your Interface Builder document. The default behavior of a View Controller is to load its view from Interface Builder files. And by doing so you get to avoid writing a lot of code.

If any of you were here in the session that immediately preceded this, you saw that just by using Interface Builder, we were able to reduce our code size by 42%. And there are two ways to create View Controllers that I mentioned: Static and On Demand, and both of them work seamlessly with Interface Builder documents as their views.

And of course by creating clean separations in your code, between the things that are important to your application and the things that are important to every application but are more or less shared, you can allow Lazy Loading and Unloading and stay as performant as possible on the iPhone, which is still an embedded device. At this point I'm going to hand it over to Matt Gamble who will guide you through the rest of our tour.

So we've seen the Single Screen Application type, let's now take a look at Hierarchical Applications. And a great example of a Hierarchical Application is the Contacts app on the phone. The Contacts app manages a hierarchy of contacts going from the groups that the user has, then looking at the contacts that make up that group and then finally, looking at the individual details of a particular contact. Well how would we design this? When you're dealing with hierarchies, your first thought should be a UI Navigation Controller. And the UI Navigation Controller manages this hierarchy, by managing a stack of View Controllers.

In this case, the bottom of this stack, or the Root View Controller, would be the Groups View Controller and it would presumably be loading its interface, which in this case is this table view, from an Interface Builder document. Now when the user selects one of the cells in this table, indicating that they wish to navigate to this more fine-grained view, then the Table View Controller would message its delegate, which in this case would be the Groups View Controller.

The Groups View Controller would create an instance of a Contacts View Controller and it would then push this Contacts View Controller to the top of the Navigation Controller's View Controller stack and then the Navigation Controller would take care of animating out one view, indicating that the new View Controller should load its view and then animating that into screen in the slide motion that we're all very familiar with.

When the user selects Individual Contact, same thing would happen again. This time the Contacts View Controller would instantiate the Details View Controller, push it to the top of the Navigation Controller stack. The Navigation Controller would then animate out one view and in the other view and we would see the details for that particular contact. Now as we heard before, when you're working with View Controllers, you will usually have your view designed in an Interface Builder document.

So for each one of these particular views, we'll have a corresponding Interface Builder Document, where we can lay out our interface exactly the way we wish to see it at run time. Now since the Navigation Controller will be needed for the entire life of our application, as well as the Groups View Controller, which would be the Root View Controller and the base of this Navigation Controller's stack of View Controllers, we can embed the Groups View Controller directly within the Navigation Controller and then place the Navigation Controller as a Static View Controller in our Main Window document.

Bringing our total number of Interface Builder documents to four and this saves us a bit of code that we would have to write otherwise. As for the two remaining View Controllers, as we mentioned we would be instantiating these when the user is selecting one of the individual cells of a table.

So we'll simply create these in code as needed. So right now, let's take that demo that we worked with earlier and now move it to more of a Hierarchical Application. So to begin with I'm just going to quit the simulator and return to our To-Do Application, Xcode project. So let's go back to the Main Window Interface Builder document and take a look at that in Interface Builder.

Now we saw that Rob connected the initial View Controller outlet to our Detail View Controller, but as we're now going to be using a building a Hierarchical Application, we'll be using a table view to manage a number of various to-do tasks. So we won't actually know which particular task the user would like to look at, as it will depend on which one they select in the table. So our Initial View Controller will no longer be this Detail View Controller, as we'll be creating this on demand later.

So I'm just going to go ahead and delete this. And I'm going to drag out a Navigation Controller from the Interface Builder Library and as this is going to be our Initial View Controller, I'm going to Control click on the To-Do App Delegate and reconnected the Initial View Controller outlet to our Navigation Controller. Now I'm going to change the document window to the Outline Mode, so we can take a look a little bit more in depth as to what we are getting when we drag this Navigation Controller from the library.

If we disclose the Navigation Controller, we'll see that it comes with a Navigation bar as we would expect, but it also comes with a Root View Controller already embedded within it. And if we look at the Identity Inspector, we'll see that the class is just set to UI View Controller. Well, we're going to have to make a few changes here as we would want this to be the View Controller that would be managing our Table view.

So I'm going to Save our changes here and return to our Xcode project. So I'm going to begin by adding a new class to our Xcode project and I'm going to go to the File Menu and create a New File. And we're creating a Cocoa Touch class here as we're going to be creating the View Controller that will manage our table and if I were to select Objective-C class and disclose this Popup button, we can see that Xcode offers to create a sub-class of many different types for us; and if we were to do this it would come with some Interface Builder documents pre-configured and even some of the many methods that we would need already stubbed out and some completely implemented, which is great. But for explanatory purposes here, I'm going to go ahead and start with a sub-class of NS Object. Hit Next and this is going to be our Table View, so I'm going to called this TD Table View Controller and Rob wasn't kidding about the typing.

OK, here we have our Table View Controller. Now we said that we want this to be a sub-class of UI Table View Controller, which is a sub-class of UI View Controller that UIKit provides, that makes it a lot easier to handle table views. So instead of making this a sub-class of NS Object, I'm going to change this to UI Table View Controller and since UI Table View Controller is coming from the UIKit, I will be replacing this import with UIKit.

All right? I'll save those changes and next, since we're creating a new View Controller, well, the next step would be to create an Interface Builder document for this View Controller. And so to do that I'll go to our Resources folder and again, go to File, Create a New File. This time I'll create a user interface file and again, so that we're going to see everything that's happening here, I'm going to go with just an empty Interface Builder document.

Again call this TD Table View Controller and finish. So if we take a look at this document in Interface Builder, I'm just going to double-click it and let's go ahead and Hide Others. We'll see that all we have is the File Zoner and First Responder, we haven't actually added anything to this document yet. Well, as we know that this is going to be the Interface Builder document associated with our new Table View Controller class, I'm going to Select File Zoner and indicate this to Interface Builder by selecting our TD Table View Controller. Next we're going to need a table view.

So I'll go back to the Interface Builder library and drag out an instance of the Table view. And as we know that we want this Table view to be the view that is loaded when our Table View Controller sub-class presents its interface, I'm going to go ahead and Control-click on the File Zoner to bring up the Connections Panel and then drag from the View Well over to our Table View and make that connection.

Now if I double-click on this Table View to open it on the design surface, we can see that Interface Builder, oh, grabbed the wrong one there, we can see that Interface Builder has added some predefined data to sort of give us an idea of what this would look like.

Well to give us an even better idea of what this is going to look like, since we know that this will be in a Navigation Controller, I can go to the Attributes Inspector for the table view and then go down here to this third section from the top, the Simulated User Interface Elements and as this table view will be embedded in the Navigation Controller, which as we saw will have a Navigation bar, we can go ahead and change this top bar to Navigation bar and this gives us a better understanding of how this will actually look when the user is interacting with it.

Now we've also heard a lot about how searches come into lots of the applications on the iPhone and even to the entire system in the form of Spotlight. Well let's make sure to add Search to our application as well. And Interface Builder makes this very easy by adding not only a Search bar to the library, but also a Search bar with a pre-configured Search Display Controller.

So if I drag this from the library and over to our table view, we'd like to make it the header of our table in a similar manner as the Contacts Application and we can see that again, Interface Builder makes this easy by giving us a little drop highlight here, indicating that this will become the header of the table. So if I drop this in here, we can see it's now set as the header of our table and we also gained this Search Display Controller object in our document window.

Well let's Control-click to bring up the Connections Panel and we can see that there's a number of connections, most of which end in "delegate' or 'data source,' and since we indicated to Interface Builder that the object loading this Interface Builder document would be a sub-class of UI View Controller, Interface Builder has gone ahead and made some educated guesses and connected all these outlets to File Zoner, as most times you would have one class be acting as the data source and delegate for the Search Display Controller. Well that's exactly what we want.

So instead of wiring all that up, we'll just Save this and now let's go back to Xcode and actually implement some of these things we've been talking about. So back in Xcode I'm going to navigate to our TD Table View Controller header file and we see it's rather blank right now.

Well first I'm going to add some of the instance variables that we're going to need. And this first one and its predicate, it's our filter predicate, we'll actually be using this more later so we'll go ahead and looked at our Filtered Tasks Array and this is simply an array of the tasks that we'll be displaying in our table. And finally we have another NS predicate and this is our search predicate and this is the one that we will construct using the information that the user enters into our search bar so we can know to filter our results appropriately.

We're also going to have some properties-we'll have four properties, ones to match our instance variables for our filter predicate, filtered tasks and search predicate and we'll also have a read only property for our search results and this will be the collection of tasks that match the predicate that we built from what the user typed into our search bar. All right, that's great.

So I'm going to Save this. And I'm going to go over to our TD Table View Controller Implementation file. So first, a little memory management. Add or DeAlloc method, making sure to release our instance variables. And then as we had four properties, we're going to have to declare them here so we'll be synthesizing the filter predicate, filtered tasks and search predicate properties and we're actually going to have a little bit more work in our filtered tasks method and we're going to check and see if we've already instantiated it and if not we'll see if we have a filter predicate If we do, then we'll filter the task that we get back from the Shared Task Vendor, otherwise we'll simply get a copy of the tasks. Well since we'll be using the TD Task Vendor class, I'm going to add an import statement. Now we saw in the header file, I added four properties. But I've only synthesized three.

Well we're actually going to be declaring one of them as dynamic, meaning that we'll supply the implementation of the method ourselves and as this was marked as a read only property, we only need to implement the getter for this property. And our getter simply acts a lot like our filtered tasks, checking to see if we have a search predicate and if we do, making sure to filter our tasks otherwise just returning the array of tasks that we have on hand.

Now you saw that I dragged in a UI Table View into our interface and a table view. Using a table view in your application deserves a little bit more explanation. When you're using a table view, the table view has both an object acting as a data source and another as its delegate.

Now the data source is an object that helps the table view populate itself with the data that you'll be wanting to show to the user and the delegate is an object that configures some more specific behavior and maybe adjusts some of the options and how things will look. Well as we made our sub-class here a sub-class of UI Table View Controller, this class will be acting as both the delegate and the data source for our table view that we added in Interface Builder. So I'm going to go and add these properties or add these implementations.

First, we're going to need a little helper method to distinguish between some of the different kinds of tasks we have and this is tasks for table view. You might be asking, why do we need to distinguish this? We only saw one table view get dragged into Interface Builder. And that's true, I only dragged one out and that would be the table view that belongs to our Table View Controller sub-class.

Well the Search Display Controller also uses a table view when it's showing the lists of tasks that will match the search results that the user entered into the search bar. It'll present those in its own table view so that the user can then select from there. So to make sure that we're returning the correct tasks, we're going to check and see if the table passed in is our table that we configured in Interface Builder. If it is, then we'll know we need to return our set of tasks, otherwise we'll return the search results.

So now onto the table view data source protocol and the first method we'll be implementing is the Table View Number of Rows and Section method, where we'll need to return simply the number of rows in the section of our table view. And as our table is the standard style rather than the group style, we'll have only one section. So we will return the count of the task for the corresponding table. The second method requires a little bit more work and this is the Table View Cell for Row with Index path.

Now again, it's another part of using table view that requires a little bit of explanation, and that is the fact that it recycles the cells that it uses to populate its table, only ever having enough in memory to display the cells that are necessary on screen at that particular moment. Then has a recycling mechanism that allows you to reuse cells that have either fallen off the top or dropped off the bottom and then you can simply reset the information in those cells and use them again rather than allocating an entirely new object.

So we're going to take advantage of that here. So first we'll get the corresponding task at this index path for the correct table and then we'll ask the table to de-que a reusable cell that matches the identifier that we'll pass in. And this allows, gives the table a chance to give us a recycled cell that matches our identifier.

If we get, if we do not have a recycled cell to use at this point, we'll have to actually create, allocate, and init one ourselves using the Init with Style Reuse Identifier Method, and for the style we'll be passing in the table view Cell Style sub-title, which has a nice looking title and then a somewhat smaller and different colored sub-title underneath. Looks very nice.

And we'll be passing in our reuse identifier to be sure that we can indicate the correct type of cell we wish to reuse when we are asking the table to de-que one. Now regardless of whether we're reusing a cell or we've created a new one, we'll have to set some of the properties, and in this case we will be setting the text of the cell's text label to the title of our task and we will be setting the text of the cell's detail text label to whether or not the task has been completed. And again, since we'll be using this TD Task class for the first time, I'm going to go back up to the top here and make sure to add that import statement.

So those were those data source methods from that table view data source protocol that I mentioned, but we haven't done anything with that delegate protocol that I'd talked about. So here it is. The only method for the table view delegate protocol that we'll be implementing is the Table View Did Select row and index path method and this is our chance to react to the user selecting one of the cells in our table view.

And in this case what we want to have happen is similar to with the contacts application, they select the row in the table and then our detail view that Rob created earlier would animate into place. So we'll get the appropriate task and then make sure to create an instance of the Detail View Controller that Rob mentioned earlier. And we'll use the init with Nib name, making sure to pass in the name of the Interface Builder document that Rob slaved over. And then we'll set the task to our current task and then set the title to the title of the current task.

And then we'll make sure to push this View Controller to the top of the Navigation Controller's View Controller stack, indicating that we do want it to perform the side-sliding animation. All right, since we used our TD Detail View Controller for the first time, I'm just going to jump up to the top here and make sure to add that import statement.

All right, returning back to where we were. There's one final method we need to add here and we have actually not dealt with our Search Display Controller very much yet, other than determining which task to use. So we have one method that we'll be using and this is another Delegate protocol, this time the SearchBarDelegate Protocol and this method, Search Bar Text Change, simply informs us that the user has changed the text that they had in the search bar. In this case we'll want to make sure to update our search predicate to reflect the search text that the user has entered and our predicate will simply match the title using a case insensitive search.

So let's Save our changes here. And let's go back to the Main Window document in Interface Builder. And I'll just hide the others. So I mentioned when we dragged out this Navigation Controller, that it came with a sorry, Root View Controller already embedded within it. But we also mentioned that this was simply a vanilla UI View Controller. Well, we would like this instead to be our new TD Table View Controller class. So in the Class Popup Button, I'll simply Select our TD Table View Controller.

If we look at the editor for the Navigation Controller, we'll see that it actually says, Root View Controller right in the navigation bar. Now Interface Builder is making sure to display in the navigation bar of our Navigation Controller, the title of the navigation item more specifically of the navigation item of our Root View Controller, which we have just modified to be our Table View Controller.

Now, we certainly don't want it to say Root View Controller, so I can simply go to the editor, double-click, select this text and replace it with something that makes a little bit more sense in our case. So I'll save these changes and one more time, let's return to Xcode.

Now at the end of his demo, Rob added a few lines to our To-Do App delegate and we're actually not going to be needing those any longer, as we're using our Static View Controller, our Navigation Controller, embedded directly within our Main Window document. And as we'll be creating our Detailed View Controller dynamically in response to users selecting a row in the table, we don't need to configure it in Application Did Finish Launching.

So I'm going to just get rid of these top four lines and we also won't be needing these import statements. Save these changes and let's Build and Run. Here it is. We see we have our tasks all set up here, showing in our Navigation Controller. And it looks like I didn't save some changes that we made, since we don't seem to have our search bar here. So I'm going to Quit this and return to Interface Builder for just one moment. And make sure to go back to our Table View Controller here and make sure that we have this all set the way that we need.

All right. What I didn't do here was I didn't indicate to Interface Builder that we'll be needing to be using the view that we created in our other Interface Builder document. So in the Nib name, we'll have to make sure to tell it that we want to use the TD Table View Controller Interface Builder document.

Save these changes. Returning to Xcode, we should see something more along the lines of what we wanted. So here we see all our tasks, in the table view. We can perform a search. All right, that works great. What about something else? Oh, yes, I want to make sure to do that. If we select one of the tasks, we can see that the detailed view that Rob created earlier animates into place and everything is working exactly the way we want.

So let's take a look at some of the key points from this demo. The first of which is we saw that we could save ourselves writing a little bit of code by adding our Static View Controllers, in our case the Navigation Controller and its Root View Controller, directly into our Main Window document in Interface Builder.

And we also saw that when the user selects one of the rows of our table, we can just dynamically instantiate one of our Detail View Controllers right in that method and then push it on to Navigation Controller's View Controller stack and have it animate into place in the manner we're all familiar with. So the final type of application design that we'll be discussing today is the Tabbed Application.

And a great example of the Tabbed Application is the Clocks App on the phone. With the Clocks App, we've got four distinct pieces of functionality that are all related in that they have to do with time, so it makes sense for them all to be in the same application, but there's no hierarchy of data here so a Navigation Controller really wouldn't make sense. But as these are distinctly related and it would be logical that they would be in the same application, we can use the Tab Bar Controller to make it easier for the user to select the different modes.

So in the same manner that we had in Navigation Controller acting as our primary View Controller guiding us through our hierarchy, in this case we begin with a Tab Bar Controller. And the Tab Bar Controller manages a collection of View Controllers that correspond to the tabs that you will have and be presenting to the user. So when the user selects a particular tab, the Tab Bar Controller makes that the Visible View Controller and if its view is not loaded it would then indicate that it should load its view, which presumably would be coming from an Interface Builder document.

Again, if someone were to select the Alarm tab, the Alarm View Controller would then become the primary View Controller and it's view would be loaded if it wasn't already and the same with the Stop Watch View Controller and again with the Timer View Controller. Now if we were constructing this in Interface Builder, how would this look? Well, we know that the one-to-one rule is a great guideline, so for each one of these View Controllers we would have a different Interface Builder document, which would provide great separation, would allow us to construct our interfaces in Interface Builder, dragging, dropping and making it look exactly the way that we want, and it would also allow the View Controller to use its memory management system.

Now in a similar manner that we embedded our Navigation Controller directly in our Main Window document as we knew that we would need it immediately and for the entire life of our application, we're also going to need the Tab Bar Controller and we also know exactly what tabs to present to the user. So we can go ahead and embed those directly in the Tab Bar Controller and then place the Tab Bar Controller directly in our Main Window document, bringing our total number of Interface Builder documents to 5.

So let's return to our demo and this time modify our Hierarchical Application and make it more of a Tab Based Application. Now for this part of the section of the demo, we're going to use the tabs to provide the user a way to look at the data in different ways.

More specifically, we're going to have the first tab be all of our tasks, the second tab be only the tasks that are currently in progress, and then the third tab be just the completed tasks. So the first step is to take a look at our Main Window document again and as we will be needing a Tab Bar Controller, I'm just going to go back to the Interface Builder library and drag out an instance and drag that into our document window.

Now in a similar manner to the Navigation Controller, the Tab Bar Controller comes pre-populated with a couple of tabs, so you could go ahead and change these to your particular sub-classes or use them as-is or simply change the views that they'll be loading to load your views. But we already have everything configured in the form of our Navigation Controller with a Table View Controller already embedded within it.

So for now, I'm just going to select both of these and remove them. And next, since our initial View Controller will no longer be our Navigation Controller, but our Tab Bar Controller, I'm going to disconnect that outlet and connect it instead to our Tab Bar Controller. Now I mentioned that the tabs of this Tab Bar Controller will be different views on our same data, so we can actually just reuse our same Navigation Controller with the table view embedded. So I'm going to select that Navigation Controller, go to the Edit menu, Duplicate once, and Duplicate again. This is definitely better than writing code. And then I'm going to go and drag these just directly into the tab bar of our Tab Bar Controller. One, two, three.

There are our three tabs and now a little bit of typing as this is a little bit hard to understand what's going on. I'm going to simply double-click in the Editor for the title of this tab bar item, change this to All Tasks and then just Select this and Copy it.

Then hit Return and Editing and then do the same with the navigation item. Paste that in, hit Return. The second one is going to be our In Progress Tasks, again Select All that, have to type again, double-click, Paste, Return. And the final one will be our Completed Tasks.

[ No speaking ]

All right. So we have the look that we want, we're using our Navigation Controllers with our Table View Controllers and we have our titles and everything configured the way we want, but right as it stands right now, we have no way to differentiate between these different tabs in our Tab Bar Controller.

We have no way to say, to know in code which one of these should be getting which search predicate or which filter predicate So what we need to do is make sure that we have a handle on these navigation or on these View Controllers so we can disinvigorate them.

So to do this I'm going to return to Xcode and start by taking a look at the To-Do App delegate. The header file more specifically. And we're going to need a couple of instance variables, so I'm going to add these here. So we'll have the Tasks in Progress Table View Controller and the Tasks Completed Table View Controller and we'll have some properties for accessing these and we're also going to need a At Class statement, make sure we don't get any build warnings. So I'll Save this file and now go over to our implementation file and we're going to have to synthesize these new properties, so I'll make sure to do that.

And again, we're going to have to import our Table View Controller header file and we've got a couple of more instance variables we want to make sure to clean up after ourselves. And then finally here's the actual meat of what we're doing, modify the application Did Finish Launching method to set the filter predicates to the appropriate NS predicates, and this is that filter predicate property that I kind of glossed over during the Navigation Controller demo. And in this case we want to set the Tasks in Progress table View Controller's predicate to make sure that we are using, we are seeing only tasks that are not complete, i.e., in progress and then the opposite with our Tasks Completed controller.

So let's make sure to Save these changes. And I'm going to go back to Interface Builder and take a look again at our Main Window document. And we created outlets for these various View Controllers, but we didn't actually make any of the connections yet. So I'm going to disclose to make sure I can see these, the In Progress table View Controller and the Completed table View Controller, let's make that a little better.

And I'm going to Control-click on the To-Do App delegate to bring up the Connections Panel. And we see that the outlets that we created in Interface Builder are there and so we can create our, we can connect our Tasks Completed outlet directly to our Completed Tasks table View Controller and our Tasks in Progress outlet to our In Progress table View Controller, close that, save and return to Xcode.

So now let's Build and Run and take a look at what it looks like now. So you can see we again have our Navigation Controller from our previous section of the demo, but we now have these tabs and we have all of our various tasks here, but if we navigate to the In Progress Tasks, we see only the tasks that are currently in progress and Completed Tasks again only the tasks that have been completed. But all of our searching works correctly and we can still navigate to our detail views.

So a few key points to take away from this demo. The first is that again, as our tab bar controller would be needed at application launch and throughout the life of our application, we added it directly to our Main Window Interface Builder document as a static View Controller and this saved us having to allocate and initialize this in a particular spot in our code.

We also saw that as we knew exactly which View Controllers we would have corresponding to each of our tabs, we could add these directly to the Tab Bar controller so that we could see the way it would look in Interface Builder, rearrange them, easily retitle them and make sure that everything is going to look exactly the way we want. And we can rest assured that the views will, as we are using separate Interface Builder documents for the views of each of these View Controllers, we can rest assured that they will only be loaded when needed and will be unloaded when they are no longer needed.

So we've covered a lot of material here today, but I hope you get a better understanding on how you can use Interface Builder to design really great iPhone applications. And there's a few key points to remember when you go off to the labs after this and start constructing your applications.

The first is that a great way to think about an iPhone application is a hierarchy of View Controllers and these could be Tab Bar controllers or navigation controllers or your own sub-class, but there's always a lot of View Controllers interacting. Also good to keep in mind that View Controllers are responsible for a single view.

There may be additional outlets in your View Controller sub-class, but a primary view, which should be associated with each of these View Controllers. And the easiest way to construct and compartmentalize this view is with an Interface Builder document, so you can construct it in Interface Builder and lay it out exactly the way you want your users to see it.

And finally, we saw that there's a couple of different ways to instantiate View Controllers, for View Controllers we'll need right away at application launch or when a particular Interface Builder document is loaded into memory, we can add these as instances directly into those documents, simply dragging them from the Interface Builder library and then set them up and making sure, as we saw, to configure their views with the other Interface Builder documents where we've designed their views.

But we also saw that especially in the case of our table view example, we would want to dynamically create these View Controllers in response to the user's actions. For more information, please contact Michael Jurewitz our Developer Tools Evangelist and there's plenty of great documentation on all the subjects that we've covered here today, in particular, the Human Interface Guidelines and the Interface Builder User Guide.