Wednesday, November 18, 2009

Objective-C Object Instantiation

Today we'll go over the syntax to create an instance of a class.

In Java (and C++, to dynamically allocate an instance of a class), you use the new keyword. Objective-C's equivalent is the alloc keyword.
I wish I could say that's the end of the story, but there is a bit more.

As in Java and C++, a constructor, and its superclass' constructor, and the superclass' superclass' constructor, and so on, are called in order from superclass to subclass to its subclass, etc.
In Objective-C, constructors are called initializers, and you can consider the init: method to be equivalent to a default initializer; i.e. one that takes no arguments and is supplied by the compiler unless you specify one yourself.

What if you wanted to create initializers that take arguments? By convention, it's recommended to:
  1. begin the initializer name with init
  2. name the initializer to include the word "with"
An example might be on a Person class: initWithGivenName: (NSString*) name
Another convention is that the initializer initializes only the attributes that need to be initialized, and any other values can be set w/setter methods or through other means.

Return type
A"gotcha" compared to C++ and Java: the return type on these initializers have a return type of (id), not the name of the current class.

Designated initializers
Objective-C has the concept of a designated initializer. This is defined as the one that guarantees that all instance variables are initialized. While your subclass does not necessarily have to invoke a designated initializer on its class, it eventually must call a superclass' designated initializer. NSObject, the superclass of all classes, which is similar to Object in Java, contains a designated initializer called simply, init:.

What to return in an initalizer
An initializer either returns "self" which is like "this" in Java and C++, upon successful initialization, or nil if a failure occured.

Ok, so how do I put this all together?
Although you could make two separate calls and "throw away" the value of alloc, it's not recommended. The convention is to chain the calls together on one line like this:

SomeClass *pointerToSomeClass = [[ SomeClass alloc] init];