Objective-C Programming_ The Big Nerd Ranch Guide - Aaron Hillegass [69]
Build and run the application again. Now you can save and load task lists.
Challenges
Add a Delete Selected Item button.
Look up the NSError class reference in the developer documentation and create new NSError instances to hand back when saving and loading fails, as mentioned at the end of the chapter.
Part V
Advanced Objective-C
You now know enough Objective-C to get started with iOS or Cocoa programming. But don’t rush off just yet. These next chapters provide a gentle discussion of techniques and concepts that will be useful in your first year as an Objective-C programmer.
29
init
In the class NSObject, there is a method named init. After an object has been allocated, you send the init message to the new instance so that it can initialize its instance variables to usable values. So alloc creates the space for an object, and init makes the object ready to work. Using init looks like this:
NSMutableArray *things = [[NSMutableArray alloc] init];
Notice that init is an instance method that returns the address of the initialized object. It is the initializer for NSObject. This chapter is about how to write initializers.
Writing init methods
Create a new project: a Foundation Command Line Tool called Appliances. In this program, you are going to create two classes: Appliance and OwnedAppliance (a subclass of Appliance). An instance of Appliance will have a productName and a voltage. An instance of OwnedAppliance will also have a set containing the names of its owners.
Figure 29.1 Appliance and its subclass, OwnedAppliance
Create a new file: an NSObject subclass named Appliance. In Appliance.h, create instance variables and property declarations for productName and voltage:
#import @interface Appliance : NSObject { NSString *productName; int voltage; } @property (copy) NSString *productName; @property int voltage; @end (We’ll talk about the copy property attribute in Chapter 30.) In Appliance.m, synthesize the properties to create the accessor methods for the instance variables: #import "Appliance.h" @implementation Appliance @synthesize productName, voltage; ... You would create an instance of Appliance like this: Appliance *a = [[Appliance alloc] init]; Note that because Appliance doesn’t implement an init method, it will execute the init method defined in NSObject. When this happens, all the instance variables specific to Appliance are zero-ed out. Thus, the productName of a new instance of Appliance will be nil, and voltage will be zero. A basic init method Let’s say that every instance of Appliance should start its life with a voltage of 120. In Appliance.m, override NSObject’s init method by adding a new implementation of init. - (id)init { // Call the NSObject's init method self = [super init]; // Give voltage a starting value voltage = 120; // Return a pointer to the new object return self; } Now when you create a new instance of Appliance, it will have a voltage of 120 by default. (Note that this doesn’t change anything about the accessor methods. After the instance is initialized, it can be changed just as before using setVoltage:.) Notice that you called the superclass’s init method, which initializes the instance variables declared in the superclass and returns a pointer to the initialized object. Most of the time, this works flawlessly. However, a few classes have deviant init methods. Here are the two possible forms of deviance: The init method figures out a clever optimization that it can do, deallocates the original object, allocates a different
In some cases, an initial value of zero for your instance variables may work fine. In others, however, you’ll need instances of your class to come into the world with their instance variables initialized to non-zero values.