Cocoa Programming for Mac OS X - Aaron Hillegass [45]
NSController is an abstract class (Figure 8.1). NSObjectController, a subclass of NSController, displays the information, or content of an object. NSArrayController is a controller that has an array of data objects as its content. In this exercise, we will use an NSArrayController.
Figure 8.1. Controller Classes
Starting the RaiseMan Application
Over the next few chapters, you will create a full-featured application for keeping track of employees and the raise that each person will receive this year. As this book progresses, you will add file saving, undo, user preferences, and printing capabilities. After this chapter, the application will look like Figure 8.2.
Figure 8.2. Completed Application
(Yes, experienced Cocoa programmers, you could create an application like this using Core Data, but we want you to see how it is done manually. Then, Core Data will not seem so magical.)
Create a new project in Xcode. Choose Cocoa Application for the type. Name the project RaiseMan, set the Class Prefix to RM, and enable Create Document-Based Application. Set the document extension to rsmn, and disable Use Core Data and Include Unit Tests (Figure 8.3).
Figure 8.3. New Document-Based Project
What is a document-based application? It is an application in which several documents can be open simultaneously. TextEdit, for example, is a document-based application. System Preferences, on the other hand, is not a document-based application. You will learn more about document architecture in Chapter 10.
The object diagram for this application is shown in Figure 8.4. The table columns are connected to the NSArrayController by bindings rather than by outlets. This is a cell-based table view; we will discuss view-based table views in Chapter 11.
Figure 8.4. Object Diagram
Note that the class RMDocument has already been created for you. RMDocument is a subclass of NSDocument. The document object is responsible for reading and writing files. In this exercise, we will use an NSArrayController and bindings to construct our simple interface, so we won’t be adding any code to RMDocument just yet.
To create a new Person class, choose the File -> New -> New File... menu item. When presented with the possibilities, choose Objective-C class. Name the class Person and set it to be a subclass of NSObject, as shown in Figure 8.5.
Figure 8.5. Creating a Person Class
Edit the Person.h file to declare two properties:
#import @interface Person : NSObject { NSString *personName; float expectedRaise; } @property (readwrite, copy) NSString *personName; @property (readwrite) float expectedRaise; @end Now edit Person.m to synthesize these properties and to modify the overriding init: #import "Person.h" @implementation Person @synthesize personName; @synthesize expectedRaise; - (id)init { self = [super init]; if (self) { expectedRaise = 0.05; personName = @"New Person"; } return self; } @end Note that Person is a model class—it has no information about the user interface. As such, this class doesn’t need to know about all the Cocoa frameworks. Thus, instead of importing Cocoa/Cocoa.h, we are importing Foundation/Foundation.h. Either would work, but importing the smaller framework is more stylish. It indicates, for example, that this class could be reused in a command-line tool or an iOS application. Declare the employees array (which will contain instances of the Person class) in RMDocument.h: @interface RMDocument : NSDocument { NSMutableArray *employees; } - (void)setEmployees:(NSMutableArray *)a; @end Now in RMDocument.m, modify init to instantiate the employees array. Create the setEmployees: method. Leave the rest of the template methods in place for now. - (id)init { self = [super init]; if (self) { employees = [[NSMutableArray alloc] init]; } return self; } - (void)setEmployees:(NSMutableArray *)a { // This is an unusual setter method. We are going to