Chapter 5
Object Initialization and Deallocation
iSimplePlug Documentation
We now switch focus to the implementation file, "SimplePlug.m", which contains the actual code that is compiled.
The initWithOwner: Method
The first task at hand it so make sure the object can be instantiated properly; that is, memory can be allocated for its instance variables and then given some initial values. Objective-C handles the allocation of memory for us, however we must implement the initialization routine ourselves.
The initialization routine must accomplish several tasks, including making the superclass initialize itself, initializing the instance variables, and then returning the resulting object. The following code (placed in the SimplePlug
@implementation
block accomplishes this:
- (id)initWithOwner:(ITonamaton *)ownerObj
{
//Initialize the plugin.
if(self = [super initWithOwner:ownerObj] )
{
//Initialize the command name array.
commandNameArray = [[NSArray alloc] initWithObjects:@"monkey",
@"cow",
nil];
//Initialize the command ID array.
commandIDArray = calloc( [commandNameArray count], sizeof(unsigned) );
if( !commandIDArray )
{
[self release];
return nil;
}
}
return self;
}
The first line of this code declares the initWithOwner:
method. In this case, we declare our initWithOwner:
method to take a pointer to the ITonamaton
object which owns all the plugin instances. (It is this object which allocates and initializes our plugin.)
The following if
statment is a standard practice on all init methods. It does several things. It first initializes the superclass to point to the plugin's owning iTonamaton
object, via the [super initWithOwner:ownerObj]
method call. Next, the statment sets the special self
variable to point at the value that was passed back from the initialization of the superclass. Finally, we get to the if
statment. In this case (as is the case for all objects in Obj-C), there are certain conditions which can cause the return value of the initialized superclass to be nil
. Hence, the if
statment is really a compound statment that checks the value of self
after the super class is initialized and self
is set to point at the returned value.
The value of a pointer evaluated in an if
statement is YES
(which is Obj-C code for true) if the pointer points at anything other than nil
. (This, of course, implies that it returns NO
when the pointer evaluated in it is nil
.) Therefore, if self
is nil
, the initialization routines in the if
block will not be executed. This is important, because if the returned value is indeed nil, accessing its instance variables will crash the program, as they do not exist.
Did you catch all that? For one innocuous looking line of code, it really does a lot. You might want to take another look at the last paragraph before continuing. Then again, you might want to just ignore it for now, instead just remembering the construct for your mental library of code snippets.
We next come to the initialization of the commandNameArray
. In this statement an NSArray
is allocated and then the allocated object is initialized with a list of objects. In this case, the list of objects is the commands that this plugin responds to (these being !monkey and !cow). One should observe that the commands in the commandNmaeArray
are sans the leading exclamation point. This exclamation point is striped by iTonamaton before the command is passed to the plugin.
Note that the last object in the array is nil
. It is mandated by NSArray
that NSArray
s initialized with the initWithObject:
method end with nil
. Failure to do this results in a broken program.
One variable initialization down, one more to go; on to the commandIDArray
instance variable:
The commandIDArray
variable is a pointer to C Array that is used to cache the numeric IDs that iTonamaton assigns to each command. It is these numeric IDs that are passed, via the NSNotification
, to plugins for processing. For several alternate methods of handling cacheing, see Appendix A.
Now, since commandIDArray
is a pointer to a C array, the code drops into a little ANSI C here. What happens in this line is that the memory for the array is dynamically allocated using the calloc
function, and the resulting pointer to that memory is assigned to the commandIDArray
variable. The first argument to calloc
is the number of elements in the array, and the second argument is the size, in bytes, of each element of the array. In our case, the IDs are unsigned
values (which are like int
values, except they all must be zero or higher).
This is probably a technical detail, so if you think you might confuse easily, skip this paragraph. It is probably wise to note that malloc
(which calloc
most likely just calls with the appropriate argument) is used by the NSObject
alloc
class method to allocate the memory for objects (i.e. class instances). So in a sense, we are accomplishing most of the same thing the alloc
method accomplishes, minus some Obj-C specific tasks.
The final if
statement checks to make sure that calloc
didn't fail and retun a NULL
value. If it did return a NULL
, then our object failed to initialize properly, and we return nil
to the rest of the program. Note that we call release on self
so that the object being initialized is released. If [self release]
fails to be called, then our program would have a memory leak.
It might be good to note that calloc
pretty much never returns NULL
. Running out of memory is the most likely cause of this problem.) Therefore, one could get away with not doing the NULL
check. However, a good coder endeavors to make their code robust when possible, and thus includes this statment just in case. It is considered bad form to ignore the possibility of calloc
returning NULL
Lastly, the initWithOwner:
method returns the value of the pointer self
. Init methods usually return a pointer to self
before they exit.
The init Method
Although iTonamaton never calls it, it is considered bad form to not override the init
method with a custom implementation for each class. Fortunately, we can utilize what was written in the initWithOwner:
method to do the real work for us. The following code is as good of an implementation of init
as one could expect for not being provided a pointer to an owner:
- (id)init
{
return [self initWithOwner:nil];
}
The previous method merely passes off the task of initialization to the initWithOwner:
method, giving it a nil
reference for the owner. It then returns the result to the caller.
The dealloc Method
Cocoa uses reference counting for its memory management technique. When the reference count on an object reaches zero, the object is automatically deallocated from memory. However, before the object is deallocated, that object must be sure that the objects it has created are properly released. (Note that these objects are released, not deallocated, as other classes may have references to some of these objects.) The way Obj-C handles this is that when an object is deallocated, it's dealloc
method is called.
In the iSimplePlug plugin, the dealloc method must do two things: First, it must release the NSArray
of command strings, commandNameArray
. Second, it must release the memory used by the C Array of cached command ID numbers. The code to accomplish this is as follows:
- (void)dealloc
{
[commandNameArray release];
free( commandIDArray );
[super dealloc];
}
The releasing of the NSArray
commandNameArray
is straight forward Cocoa memory management. However, since commandIDArray
is a C Array, Objective-C memory management does not work on it. Therefore the ANSI C function free
is called, passing it a pointer to the space to deallocate. Finally, the superclass of our plugin is told to execute its dealloc
method, thus allowing the superclass to clean up and deallocate properly. (A failure to forward the dealloc
call to the superclass will result in memory leaks!)
A note for the technically inclined: part of what happens when an Obj-C object is deallocated, is that the free
function is called on the space that the object occupied.) Of course, you don't need to know this, but it is still nice to know, eh?
[back]
[TOC]
[forward]
Last Modified: $Date: 2003/12/16 01:29:33 $ by $Author: paploo $