1.4 Creating Object Instances

One of the principal functions of a class object is to serve as a factory for creating new instances. When new objects are created, memory is allocated and its instance variables are initialized. This is accomplished by using the alloc method, defined by the NSObject class, as follows:

Song song = [song alloc];

The alloc class method dynamically allocates memory, sets the isa variable to a pointer to the class's class object, sets all other variables to 0, and then returns the new object instance. This takes care of the system level tasks that need to be performed when an object is created, but doesn't allow the object to properly initialize itself. To give an opportunity for object-specific initialization, the NSObject class provides the init instance method. To fully create an instance of the Song class, use the following code:

Song song = [[song alloc] init];

The init method can be overridden in a subclass to assign defaults to instance variables and to take care of other tasks that need to be performed before an object is used.

You can call the alloc and init methods by using separate lines of code. However, since object allocation and initialization are interlinked, calling both methods with one line of code is good practice.

When you override the init method, the superclass's init method (or designated initializer, as covered in the next section) should always be called to ensure that the superclass is initialized properly. Initialization methods should also return self, the object being initialized. Example 1-6 shows an init method for the Song class.

Example 1-6. An initialization method for the Song class
- (id)init {                                     // 1
    self = [super init];                         // 2
    // ... Song-specific initialization code
    return self;                                 // 3
}

The code shown in Example 1-6 performs the following tasks:

  1. Declares the init method, which returns an object of type id. The returned object is the newly initialized object.

  2. Calls the init method of the superclass (super) to let it properly configure its state. The self variable is set to the return value of the init method because it might return a different instance than the one currently being worked with.

  3. Returns the object using the self variable.

Initialization methods return an object of type id so an initialization method can actually return a different object of a different type, if necessary. For example, if a class needs to return a more specialized subtype to better take advantage of a system's runtime configuration, it can release the object originally created, create a new one of the subtype, and return it. This is why programs need to use the object returned by the init method and not the object returned by the alloc method, and why you should make sure that self is set to the init method's return value.

The ability for an initialization method to return a subtype allows for a programming pattern known as class clusters. This allows for a large amount of functionality to be exposed behind a small and easy to understand public class definition. For example, there are many different string classes that are represented by the public NSString class.

1.4.1 Designated initializers

A class can provide multiple initialization methods to allow varying levels of customization. When you have multiple initializers, only the designated initializer should call the superclass' initializer method. All other initializers must call the designated initializer. This will ensure that your classes always behave properly.

For example, if an initWithTitle: method is defined for the Song class, the more general init method would first need to be called to allow proper initialization of both the Song class and its parent classes before proceeding with specific initialization. Example 1-7 shows an example.

Example 1-7. Calling a designated initializer
-(id)initWithTitle:(NSString *)aTitle {
    self = [self init];
    [self setTitle:aTitle];
    return self;
}


    Part II: API Quick Reference