3.1 Allocating and Initializing Objects
It takes two steps to create an object using Objective-C:
1. Dynamically allocate memory for the new object
2. Initialize the newly allocated memory to appropriate values
In objective-C, memory for new objects is allocated using class methods defined in the NSObject class. NSObject defines two methods:allocandallocWithZone:. They don't need to be overridden and modified in subclasses.
The alloc and allocaWithZone: methods initialize a newly allocated object's isa instance vairable so that it points to the object's class.All other instance variables are set to 0.
The initialization method begin with the abbreviation "init". If the method takes no arguments, the method name is justinit. If it takes arguments, labels for the arguments follow the "init" prefix. E.G.initWithFrame:
3.2 The Returned Object
An init... method normally initializes the instance variables of the receiver, then returns it.
If the init method cannot initialize a new object successfully, it may return nil, indicating the requested object can't be created. (e.g. file name is incorrect)
Because an init... method might return an object other than the newly allocated receiver, or even return nil, it's important that programs use the value returned by the initialization method, not just that returned byalloc or allocWithZone:
// bad implementation, ignore the return from nil
id anObject = [SomeClass alloc];
[anObject init];
[anObject someOtherMessage];
We should combine allocation and initialization messages in one line:
id anObject = [[SomeClass alloc] init];
[anObject someOtherMessage];
If init may return nil, we should check the return value before processing:
id anObject = [[SomeClass alloc] init];
if( anObject )
[anObject someOtherMessage];
else
...
3.3 Implementing an Initializer
3.3.1 Constraints and Conventions
1. The name of a custom initializer method begins with init.
2. The return type of an initializer method should be id.
3. In the implementation of a custom initializer, you must invoke the superclass's designated initializer. By default, the designated initializer is init.
4. You should assign self to the value returned by the designated initializer.???
when we do [anObject alloc], we will create a new instance. And all the self (whether in init method of anObject's class, or it's super class) will refer to the created instance. (self refer to the object that perform the method!)
5. If you set the value of an instance variable, you typically do so using direct assignment rather than using an accessor method.
6. At the end of the initializer, you must return self, unless the initializer fails in which case you return nil.
Example of custom initializer for a class inherited from NSObject and has a instance variable createDate:
- (id)init {
// Assign self to value returned by super's designated initializer
// Designated initializer for NSObject is init
if (self = [super init]) {
createDate = [[NSDate alloc] init];
}
return self;
}
3.3.2 Handling Initialization Failure
In general, if there is a problem during an initialization method, you should call [self release] and return nil.
Consequences of this policy:
1. Any object that receives a nil from an initializer method should be able to deal with it.
2. You must make sure that dealloc methods are safe in presence of partially-initialized objects.
Note: You should only call [self release] at the point of failure(we can only release the object once). If you get nil back from an invocation of the superclass's initializer, you should not also call release. This is typically handled by the pattern of performing initialization within a block dependent on a test of the return value of the superclass's initializer:
- (id) init {
if (self = [super init]) {
creationDate = [[NSDate alloc] init];
}
return self;
}
How to handle an inappropriate value passed as the parameter:
- (id)initWithImage: (NSImage *)anImage {
if(anImage == nil) {
[self release];
return nil;
}
// else do the normal work
}
3.3.3 Coordinating Classes
The init... methods a class defines typically initializes only those variables declared in that class. Inherited instance variables are initialized by sending a message to super to perform an initialization method defined somewhere farther up the inheritance hierarchy.
The message to super chains together initialization methods in all inherited classes. Because it comes first, it ensures that superclass variables are initialized before those declared in subclasses.
E.G.
- (id)initWithName: (NSString *)string
{
if( self = [super init] ) {
name = [string copy];
}
return self;
}
A class must also make sure that all inherited initialization methods work. For example, if class A defines an init method and its subclass B defines an initWithName: method. B must also make sure that an init message successfully initializes B instances.
// init method implementation on B class
- init
(
return [self initWithName:"default"];
)
The initWithName: method would invoke the inherited method, so initWithName is the
designated initializer:
3.4 The Designated Initializer
The designated initializer is the method in each class that guarantees inherited instance variables are initialized(by sending a message to super to perform an inherited method).
It's important to know the designated initializer when defining a subclass.
Suppose we deinfe class C, a subclass of B, and implement an initWithName:fromFile: method. In addition to this method, we have to make sure that the inherited init andinitWithName: methods also work for instance of C. This can be done just by covering B's initWithName: with a version that invokesinitWithName:fromFile:
// initWithName: method defined in class C
- initWithName: (char *)string
{
return [self initWithName:string fromFile:NULL];
}
We don't need to modify init method, as it's already modified in class B.
The designated initializer in a class must, through a message to super, invoke the designated initializer in a superclass.
B's init sends a message to self to invoke the initWithName: method. Therefore, when the instance is of Class B, it will invoke B's InitWithName: method; when the instance is of Class C, it will invoke C's InitWithName:
3.5 Combining Allocation and Initialization (left)
In cocoa, some classes defined creation methods that combine the two steps of allocating and initializing to return new, initialized instances of the class. These methods are often referred to asconvenience constructors.