[back]   [TOC]   [forward]


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 NSArrays 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 $