Cocoa Programming for Mac OS X - Aaron Hillegass [55]
- (void)encodeWithCoder:(NSCoder *)coder
{
[super encodeWithCoder:coder];
[coder encodeObject:personName forKey:@"personName"];
[coder encodeFloat:expectedRaise forKey:@"expectedRaise"];
}
The call to the superclass’s encodeWithCoder: method would give the superclass a chance to write its variables onto the coder. Thus, each class in the hierarchy writes only its instance variables (and not its superclass’s instance variables) onto the coder.
Decoding
When decoding data from the coder, you will use the analogous decoding methods:
- (id)decodeObjectForKey:(NSString *)aKey
- (BOOL)decodeBoolForKey:(NSString *)key
- (double)decodeDoubleForKey:(NSString *)key
- (float)decodeFloatForKey:(NSString *)key
- (int)decodeIntForKey:(NSString *)key
If, for some reason, the stream does not include the data for a key, you will get zero for the result. For example, if the object did not write out data for the key foo when the stream was first written, the coder will return 0.0 if it is later asked to decode a float for the key foo. If asked to decode an object for the key foo, the coder will return nil.
To add decoding to your Person class, add the following method to your Person.m file:
- (id)initWithCoder:(NSCoder *)coder
{
self = [super init];
if (self) {
personName = [coder decodeObjectForKey:@"personName"];
expectedRaise = [coder decodeFloatForKey:@"expectedRaise"];
}
return self;
}
Once again, you did not call the superclass’s implementation of initWithCoder:, because NSObject doesn’t have one. If Person’s superclass had implemented the NSCoding protocol, the method would have looked like this:
- (id)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
personName = [coder decodeObjectForKey:@"personName"];
expectedRaise = [coder decodeFloatForKey:@"expectedRaise"];
}
return self;
}
The attentive reader may now be saying, “Chapter 3 said that the designated initializer does all the work and calls the superclass’s designated initializer. It said that all other initializers call the designated initializer. But Person has an init method, which is its designated initializer, and this new initializer doesn’t call it.” You are right: initWithCoder: is an exception to initializer rules.
You have now implemented the methods in the NSCoding protocol. To declare your Person class as implementing the NSCoding protocol, you will edit the Person.h file. Change the declaration of your class to look like this:
@interface Person : NSObject Now try to compile the project. Fix any errors. You could run the application at this point, if you like. However, although you have taught Person objects to encode themselves, you haven’t asked them to do so. Thus, you will see no change in the behavior of your application. The Document Architecture The purpose of the document architecture relates to the Model-View-Controller design pattern discussed in Chapter 8. In RaiseMan, your subclass of NSDocument (with the help of NSArrayController) acts as the controller. It will have a pointer to the model objects, and will be responsible for the following duties: • Saving the model data to a file • Loading the model data from a file • Displaying the model data in the views
Applications that deal with multiple documents have a lot in common. All can create new documents, open existing documents, save or print open documents, and remind the user to save edited documents when he or she tries to close a window or quit the application. Apple supplies three classes that take care of most of the details for you: NSDocumentController, NSDocument, and NSWindowController. Together, these three classes constitute the document architecture.