Individually, the new technologies in Mac OS X v10.4 Tiger—Spotlight, Core Data, Core Image, Dashboard, Sync Services, Automator, and many more—present developers with a rich toolset with which to build Mac OS X applications. In fact, Tiger adds more new technologies for developers to use than any release since version 10.0 was released in 2001. Taken together, the technologies in Tiger take the platform to a whole new level. They open up possibilities for entirely new kinds of application development and change the way that you can approach developing Mac applications. It's easy enough to focus in on the details of each of Tiger's new technologies. We've done so in the articles in the Tiger Developer Overview Series. But focusing on each technology individually only goes so far. The real magic in an application built for Tiger comes from how the technologies come together and how they can build on, and complement, each other. An application built for Tiger will use many of Tiger's unique technologies together and synergistically. In fact, if you were to create a cross-section representation of an application that takes full advantage of Tiger, you could make something like the following diagram: As you can see, there are many ways in which the various technologies in Tiger can be used together. And, if an application provides a Dashboard widget or Automator Actions, the application's functionality is no longer constrained to a single process, but is spread out over many. For example, an application can use Core Data to keep its data on disk and a Dashboard widget can use that same data store in a read-only mode to present at-a-glance data to a user. Using Cocoa Makes It EasyTo illustrate how to take advantage of the new technologies in Tiger, we're going to do something a bit different and present the creation of a prototypical Cocoa application over a series of articles. This first article in this series covers the first few steps of creating our application, including putting together a data model and providing a user-interface. As we build up the application, we'll look at most of the new technologies in Tiger and how they can be utilized. When we're done, we'll have covered the spectrum of technologies that you should consider using in your own applications. Because we can't just sit down with you and your application and start adding Tiger technologies to it, we're going to start from scratch with a prototype that we can use to communicate our points. For this, we've picked a problem area that is generic enough to be familiar with every reader: that of managing to-do items. Our application will be small enough that we can focus on the points at hand rather than covering too much in the way of application specific code. We're going to call our application, simply enough, To-Do. And, not only are we going to describe it as we go, for each article we're going to provide a download so that you can look at the project for yourself to examine the details, if you are interested. This series will by no means attempt to be a "best-practices" document—our aim is simply to inspire you to think about Tiger application development in a new way. Whether you are building a new application from scratch or reworking an existing application from the ground up, you'll want to consider the approaches and ideas that we'll be covering and evaluate how you can apply them in your own development. Since we're starting from scratch, we're going to build a Cocoa application. Cocoa is the premier application framework on Mac OS X and its features and tools make creating our sample application easy. Concerning our starting point, we could begin by laying out the user interface in Interface Builder. There is, however, a much more appropriate place to start for our purposes. Instead of laying out the View (in Model-View-Controller pattern terms), we're going to start out with the Model. Designing the Data Model
The To-Do application's model is a simple set of to-do items. In Core
Data parlance, the model will be a set of
There are many other attributes that we could possibly associate with a
Even though we don't want to expose too much to the user, there are a few more things that we should capture about each to-do item for our application's internal use. These are:
These bits of information are latent data. It's data that can be placed into the model by our application, but which a user doesn't directly add. We can use this to later add informative messages to the user, such as, "It's been 43 days since you created this item." When designing your own data models, you should look for places where you can pick up interesting data that can be useful but which isn't directly entered in by the user. Implementing the Data ModelNow that we know what the data model is going to look like, let's implement it. The first thing to do is to launch Xcode 2.0 and create a new project. For our application, we're using the Core-Data Application project template. This gives us a single window application and creates an empty Core Data model that will store its data in the ~/Library/Application Support/ folder.
Once created, we see that our project has been set up to link against
the Cocoa framework, which includes the AppKit, Foundation, and Core Data
frameworks. We also have a nib file for the user interface, an
application delegate class, and a data model file,
As we discussed, our model is relatively simple and requires only one entity: ToDoItem. Create this entity using either the Design > Data Model > Add Entity menu or the (+) button under the Entity list view in the design view. To this entity, we define the following attributes:
Once the attributes have been defined, they show up in the modeling tool Inspector as follows: This is obviously a very simple data model, but our application has simple needs. Now that we've defined this model, we can let CoreData handle the rest of the details of managing the to-do items and persisting them to disk. We also will be able to easily hook this model up into our user interface and take advantage of automatic undo and redo. Test Driving the Model
At this point, we'd like to build and run the application to see what we've done. But since we started with the model, we don't have a user interface yet, right? Well, that's true, but we can fix that very quickly by opening up the
When we do this, Interface Builder responds with a dialog that asks us
whether we want to manage one item or multiple items of our model
object. Since we're going to have multiple to-do items, we answer that
we want to manage multiple objects. Interface Builder then creates an
interface that exposes all of the attributes of the
Now, when we build and run the application, we can create some to-do items and work with the model. In essence, we're test driving the model before writing the real user interface. We can also see how Interface Builder hooks into our model by using the Inspector to see the bindings settings for the various user interface components, as shown in the figure to the right.
This obviously isn't a great interface to ship to our users, but it lets us experiment with the model under the application and make sure that we are capturing the correct data. We can even quit and relaunch the application and the data persists to the Now that we have a working data model and we're pretty happy with the way it works, it's time to move on and create a user interface that we'd like our users to use. Creating a User InterfaceEven though our To-Do application is simple, we still want it to have an effective interface. And, as tempting as it is to use Interface Builder and drag out elements, sometimes the best approach is to start with a low-tech solution: pen and paper. Or maybe even a whiteboard. After sketching out several possibilities and talking through them with trusted colleagues, we ended up with the sketch to the right. The interface has a single main window and an auxiliary panel that will let the user edit some of the details of each to-do item. Like the rest of what we've done so far, it's not very complex, but that's fine.
Once we have settled on our interface, its tempting to delete the
auto-generated one that we created using the Here are the general steps we followed to build up the interface, referring to the pre-built interface's bindings settings as needed:
Now, we have a completely new interface for the To-Do application. Better yet, it's fully functional. You can add items, edit the notes associated with an item, and even change the due date. Even better, the search field works. You can type "Wat" into it and the list will change to show just the "Water Plants" entry. As well, our strategy for keeping the pre-generated has the side effect that even if we don't get something right in our new interface, we can still examine the data using the old one. There's also something going on here that you may have noticed. We haven't written a line of code. That's because we've been able to leverage the power of Core Data and Cocoa bindings. In essence, we've taken advantage of Cocoa components for all three layers of the Model-View-Controller pattern. The Model is provided by the Core Data layer. The Controller is provided by the Cocoa bindings layer. And the View is provided by Interface Builder. We're not opposed to writing code, but when the tools at hand provide the functionality needed, there's no reason to do so.
However, there's one bit of code that does need to be written to
fulfill the contract of the data model we designed. When the completed
checkbox of a to-do item is checked, we want to update the
- (void) setCompleted:(BOOL)completed { [self willChangeValueForKey:@"completed"]; [self setPrimitiveValue:[NSNumber numberWithBool:completed] forKey:@"completed"]; if (completed) { [self setValue:[NSDate date] forKey:@"dateCompleted"]; } else { [self setValue:nil forKey:@"dateCompleted"]; } [self didChangeValueForKey:@"completed"]; }
This code checks to see if the At this point, we've created a basic, fully-functional application that we'll use in the next few articles, and to which we'll then add more Tiger features. Download the ProjectTo help you better pick apart what we've done here, you can download the project as it stands as a compressed disk image file. The project state is exactly at the point where the interface has been created, complete with the auto-generated window showing you the raw view into the data model.
ConclusionIn this first article in the series, we've built a simple application that takes advantage of Core Data, a technology new in Tiger, as well as Cocoa bindings, which were introduced in Mac OS X Panther. We've laid the foundation for the next few articles where we'll hook up our application to Sync Services, Spotlight, Dashboard, Automator, and more. For More InformationPosted: 2005-06-06 |