Most iOS apps have more than one view. We’ve written a cool app with one view, but anyone who’s used a smartphone knows that most apps aren’t like that. Some of the more impressive iOS apps out there do a great job of working with complex information by using multiple views. We’re going to start with navigation controllers and table views, like the kind you see in your Mail and Contacts apps. Only we’re going to do it with a twist...
The app needs to keep track of the data for the store inventory and then display it in a way that customers can search. This way, all of Rob’s vintage records are easier to find and he can start converting all that foot traffic into sales.
Your job is to create an iPhone app that displays the record location, price, and description. The app needs to list all of the records.
iOS applications were one of the first interfaces to work through touch. That, coupled with a small screen being used for a single task, leads to multiview apps being the norm. Spin City is going to need to respond to user touch by presenting more information.
Multiview iOS applications typically have some kind of overview display (called the master view), and one or more views that drill in on specific pieces of information (called detail views). Our table view acts as our master view; we need a detail view to show all of the information we want to convey.
Data frequently falls into the category of being organized into parent-child relationships, where there is a high-level piece of data with further details to follow. It happens with contacts and calendars, for example. In our case, the record data fits nicely into this model.
The table view/detail view combination is perfect for this type of data. The table view shows all of the top-level items (in this case, records) and then each detail view shows the information for each individual record.
When you build applications, give a lot of thought to how each view should be used: What’s it trying to convey to the user? How will they interact with it? Different views frequently support different use cases, so you might want to place buttons or eliminate access to some functions entirely depending on which view the user is in and what they’re trying to do.
The iOS Human Interface Guidelines (HIG) is a document maintained by Apple that gives both best practices and App Store guidelines for app interaction patterns.
When you start going through the introduction, check out the note about using navigation for hierarchical data (using a detail view). Since it’s such a common pattern, one of the app templates in Xcode is the master-detail template.
The HIG can be found online at https://developer.apple.com/library/ios/documentation/userexperience/conceptual/mobilehig/ or through the Organizer window in Xcode, search for “iOS Human Interface Guidelines.”
This is the detail view that we came up with, but it’s OK if yours was different.
We’re following the built-in Contacts app style, but application style is part of what makes each application unique. Be careful about trading style for functionality, but make sure you give your app personality. We’ll get into more details later about how to implement all of this.
You have the two views, but there’s nothing linking them. We need to set up when each should be used, how we transition between them, and what kind of information each one needs in order to do its thing.
How does the table view know what to show in the detail view? How does the user get back?
The navigation controller can handle transitions between views. There are several view transitions built in, we just need to wire things up. It provides things like back buttons, title bars, and view history so that the user can move between data without getting lost. The navigation controller handles things like sizing the views and maintaining a view stack; we just need to tell it which views we’re working with.
Now that we have a good understanding of what the app is going to do (show records and some details about them) and how it’s going to do that (using a navigation controller and a table view), we can get started. Go ahead and open up Xcode.
Choose the template.
Start a new project and choose the “Master-Detail Application.” That one comes with the basic views and the navigation controller. Change the product name to “SpinCity” and do not add a class prefix. Leave the “Use Core Data” box unchecked.
Save your new project somewhere you can find it later and Xcode will create a new iOS application with a table view master view and a blank detail view.
Open up the storyboard.
The template includes a storyboard that has all the project’s views on it, including transitions. Click on the storyboard and Xcode will open it up in the storyboard view. Let’s dig into what we get out of the box...
Jim: We need more than just the title of the album though, we need everything that goes on that detail view too.
Joe: We need to store that somewhere....
Frank: ...but data doesn’t belong in the view controllers.
Jim: Why not? The view controller knows everything that’s going on, shouldn’t it have the data too?
Frank: What happens when we need to add new albums or edit albums in a different view? Should all of our views know about the master view controller?
Joe: No, I see your point. Hey, is this a place to use MVC?
Jim: What’s MVC?
Frank: MVC is the model-view-controller pattern. It’s used in web apps all the time with things like Ruby on Rails. It means we keep the visual presentation (the view) separate from the business logic (the controller) separate from the underlying data (the model).
Joe: But so far everything we’ve done has put the logic and the data in the same class.
Frank: Well, I think it’s time that we changed that. We need a separate class for an album and some place for them to live.
Jim: That’s fine, I guess, but what’s going in that class?
Frank: We need to define the fields for the data, build up the data model...
The MVC pattern is a common pattern in a number of frameworks and it’s all over CocoaTouch. The MVC pattern pushes you to separate the various concerns in an application into their own class or classes to help reduce the complexity in each one. iOS development blurs the view and the view controller a little, but generally you describe the view in the storyboard and keep the business logic in the view controller.
The model in MVC is conceptual—there isn’t a single class that is your model in your application. You may have a number of classes that together represent your model. The important thing is that the representation of the data in your application, and how you access that data, is a separate concern from the view and the general flow control. For Spin City, let’s start with a class that represents an album and go from there.
Get the class generated.
Right-click on the folder for Spin City in Xcode and then select New File....From there you’ll go through a dialog to create the new class. Make sure that Cocoa Touch is selected under iOS and you should see Objective-C class as a file option. Click Next. Name the class Album, select Next; save it in Spin City, in the Spin City group, and make sure that the Spin City Target is still selected. Then click Create.
We have album information that we want to be accessible to users of our Album class. To do that, we’ll declare a set of properties which the Objective-C compiler will turn into accessor methods for us to let people get to the information we want to expose. Update our Album class with a property for title, artist, summary, location in store, and price. We’re also going to tack on a method to initialize a new Album so we can set everything the way we want it whenever we create a new Album.
Here’s how we flesh out the new data model. Open up the Album header and implementation file and update them to look like this.
How are we going to load/save the actual data to put in these objects?
So now we have a class that neatly encapsulates the idea of an album, but we still don’t know where we’re getting this data from. We already talked about why we don’t want to just jam it into a view controller, so where are we going to put it and how are we going to get to it?
This is a common problem/question in iOS development. We’re getting into an important pattern here...
Just like the view has a controller, we’ll use a class to hide how we’re actually fetching the data we’re stuffing into instances of our album class. By hiding the actual retrieval, we avoid splattering SQL or web service calls all over our view controllers. We can encapsulate the data access into a Data Access Object or DAO.
Our DAO needs to take requests like “I need album 12” and translate that into a request that works with the data, gets the information back out, and passes it in some meaningful way back to the view controller.
Not this time.
Remember we’re deliberately trying to abstract away (read: hide) the implementation details of how the data is actually stored. We really have two different audiences for our DAO. We have the outside world, who want to fetch and save albums, and we have the implementation of the DAO where we need to know how we’re storing things and whatnot. To do that, we’re going to have two different interfaces: a public interface and a private interface.
That’s it! Check that you don’t have any warnings or errors and you should be all set. The app isn’t quite ready to show you any new tricks (we need to wire it up with the table view), but we have a lot to work with now.
Now we have a home for the data and a way to get at it. Next we need to wire that up to the actual view controller and table view. Just a few more steps and you’ll be able to see all those albums you just created.
You’re ready to get back in it!
Now the data and the logic to handle the data are in place. Get back in and let’s make those table views work.
Now that we know how to get to the albums, we need to get them visible on the screen. To do that, we’ll use our table view. Right now we only have a handful of albums set up, but if we were to put the whole inventory of the store in there we’d have hundreds or maybe thousands of albums to deal with. Rather than loading all of the albums and trying to jam them into the table at once, table views optimize memory usage by taking advantage of the fact that a user can’t tell if a cell that would be off the screen has any data in it or not.
UITableViews only have to display enough data to fill an iPhone screen or the view in an iPad—it doesn’t really matter how much data you might have in total. The UITableView does this super efficiently by reusing cells that scrolled off the screen.
After talking it over with Rob, we figured out he needs a summary included in the table view cell, too. Like this:
So far we’ve used the default table view cell layout in our app.
It works fine, but we want more. Tableview cells actually come with a
couple different layout styles using properties like
If those work for your application, then by all means you should use
those. We’re going to show how to build a custom cell, though, since
it’s not much more difficult and gives you the flexibility to do
whatever you want with cells.
Since we’re not going to be using a default table cell, we need
to create a new class that inherits from the basic
UITableViewCell and adds the custom properties we
want to show.
Now that the app is working and all is well, it’s time to dive into the details in the next chapter...
You’ve got Chapter 4 under your belt and now you’ve added table views to your toolbox.