Objective-C

Note: What follows is another post in an on-going series for developers who are interested in learning to write applications for the iPhone. More information about writing for the iPhone can be found here: iPhone Developer Tips .

First off, it’s worthing clarifying that much of what is covered here is as much Cocoa as it is Objective-C. However, since the two are quite closely tied when it comes to developing Mac/iPhone applications, I’ve decided to keep with the Objective-C theme as it relates to the title of this and subsequent posts.

This post will review some of the nuances of memory management. I won’t go into all the details of memory management (see Objective-C Programming Guide , Cocoa Fundamentals and Memory Management Programming Guide for Cocoa ), rather, I’ll point out some of the more subtle concepts to keep in mind as you begin to work with objects.

Object Ownership

Rule #1 – If you create an object using alloc or copy, you need to free that object.
Rule #2 – If you didn’t create an object directly, don’t attempt to release the memory for the object.

For instance, here is an object that I “own” given that I’ve called ‘alloc’ to create the object. It’s up to me to release the memory for this object:

  TestClass *ptr = [[TestClass alloc] init];
 
  ...
 
  [ptr release];

Let’s look at two examples where we are not responsible for managing the memory associated with an object. First, when using a factory (aka convenience) methods of a class. For instance:

NSString *str;
str = [NSString stringWithFormat:@"Some string here..."];
NSLog(str);

The second example, is if you call an accessor method that returns an object. Assume that the object TestClass below has a getter method that returns a pointer to an instance variable named firstName that is an NSString.

  NSString *str;
  // No need to release this object
  str = [TestClass firstName];

This makes sense if you think about it. The getter simple returns a reference (pointer) to an existing object. Now, if you want to retain (express an interest in the object to keep it around) then you would need to use ‘retain’ to bump the reference count. However, if we simply want a pointer to the object as shown here, we don’t have responsibility to release the object.

Initializing Objects

The order of things happening when initializing an object is of great relevance. For example, look at this block of code:

  TestClass *ptr = [TestClass alloc];
  [ptr init]
 
  // Do something with the object
  if (ptr)
    ...

Seems harmless enough, right? Allocate an object and send a message to initialize the object. Here’s the problem, if the init method returns nil (which all good initializers do upon failure to properly initialize an object), the code on line 5 would pass the test (that is, ptr would not be nil).

Now compare that with this approach:

  TestClass *ptr = [[TestClass alloc] init];
 
  // Do something with the object
  if (ptr)
    ...

In the code above, assuming the init method returns nil upon failure, ptr will be set to nil, and the code on line 4 would not pass the test. Much better.

So, the lesson here is twofold: always return nil from an initializer method when the method fails to properly initialize the object. Second, it’s a good practice to combine a call to alloc and init into one step. We’ll talk more about initializers in a separate post.

Releasing Objects

Let’s talk about the other end, releasing objects. Have a look at the implementation for a simple class:

#import "TestClass.h"
 
// ================================
// = Implementation for TestClass =
// ================================
@implementation TestClass
 
-(NSString *) str
{
  return str;
}   
 
-(void) setStr:(NSString *)input
{
  [input retain];
  [str release];
  str = input;
}
 
-(void) dealloc
{
  [str release];
  [super dealloc];
}
 
@end

Look at the code below that creates an instance of the TestClass, calls the setter method to initialize the ‘str’ instance variable, and releases the memory for the ‘ptr’ object.

#import "TestClass.h"
 
int main(int argc, const char * argv[])
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
  TestClass *ptr = [[TestClass alloc] init];
  [ptr setStr:@"Fubar"];
 
  [ptr release];
  [pool drain];
  return 0;
}

The dealloc method in TestClass releases the memory for the ‘str’ instance variable, and it seems all is well. However, if at some point, somewhere inside the class implementation an attempt was made to check if the ‘str’ instance variable is nil (prior to doing some operation) for example:

if (str)
  do something...
else
  do something else...

the if statement would pass and the code on line 2 would be run. Not a good thing.

A better way is to replace the call to release with a call to the setter method and pass in nil . Look at the dealloc method below:

-(void) setStr:(NSString *)input
{
  [input retain];
  [str release];
  str = input;
}
 
...
 
-(void) dealloc
{
  [self setStr:nil];
  [super dealloc];
}

The reason this works is that you can send a message to a nil object without raising an exception. If you follow the trail you’ll see inside the setStr method that the variable ‘input’ (which is nil) is sent a message to retain . This is effectively ignored, as the object is nil . The next line releases the string ‘str’. The last line sets ‘str’ to the value of the input parameter (which is nil ). This prevents the problem in the previous example where ‘str’ still had a reference to a location in memory (even though the memory had been released).

As I was getting familiar with this, I wrote a short example in Xcode. Here is the test block for the dealloc method:

-(void) dealloc
{
  NSLog(@"Address of 'str' before release is: %ld", str);
 
  // After this, 'str' still points to a memory location
  [str release];
 
  // After this, 'str' will be nil  (** This is the preferred approach **)
  //[self setStr:nil];
 
  NSLog(@"Address of 'str' is after release is: %ld", str);
 
  // Notice the result of this based on how the instance var 'str' is released (above)
  if (str != nil)
    printf("'str' still points to a memory location (after being released)!");
  else
    printf("'str' now points to nil.");        
 
	[super dealloc];
}

Notice in this case that line 6 uses release. See the output below:

Now, if you comment out line 6 and remove the comment from line 9, you’ll get the following output. Notice how the reference to ‘str’ after is 0 (nil).

You can download the Xcode project here if you’d like to take a closer look at the complete example. Hopefully this information will save you some time trying to track down an elusive memory leak.

Note: What follows is another post in an on-going series for developers who are interested in learning to write applications for the iPhone. The entire series can be found here: iPhone Developer .

This post introduces messaging within Objective-C. Messaging is the terminology for invoking methods on an object. The format for a message expression is as follows (the brackets are required):

[object method]

or in Objective-C parlance

[receiver message]

Here’s a simple example:

  // Create an instance of SomeClass object
  // We'll cover this later...
  SomeClass *ptr = [[SomeClass alloc] init];
 
  // Send the message 'printInstanceVars' to the 'ptr' receiver
  [ptr printInstanceVars];

If we want to pass an argument as part of the message (that is, pass a parameter to the method), we send a message that looks like this:

[receiver message:argument]

For example, assume setStr and setX are two methods in the SomeClass object and ptr is a pointer an instance of SomeClass . Here is how we might pass arguments to each method.

 [ptr setStr:@"Testing"];
  [ptr setX:2008];

Side note: The @ symbol at the front of @”Testing” string is convenience method that converts the given string to an NSString object, which in the case of the setStr method, is the required type for the parameter.

Nest Messages
We can also nest messages, as shown below. In this example, we first pass a message to the NSDate object. This is a class object with a factory method ‘date’ for creating a new NSDate object. If that makes no sense, don’t worry about it. Think of it as nothing more than creating a new NSDate object that holds the current date and time. The return value of inner message (the NSDate object) is the argument for setDate message. What we’ve done here is to create a new date object and pass it as an argument to the setDate message of the receiver (ptr ). Sounds more confusing than it is.

[ptr setDate:[NSDate date]];

Multiple Arguments
Taking this another step further, we can pass multiple arguments along with our message. The message below takes three arguments, a string, date and integer. Sometimes it easier to read the method aloud to get this jist of what’s up. In this case, “pass a message to the ptr receiver that sets a string, and a date and an integer.”

  [ptr setStr:@"A new test..." andDate:[NSDate date] andInteger:99];

Here is how we define the message in the interface file:

-(void) setStr:(NSString *)str andDate:(NSDate *)date andInteger:(int)x;

And here is the implementation of the setStr() method which accepts three arguments:

-(void) setStr:(NSString *)strInput andDate:(NSDate *)dateInput
    andInteger:(int)xInput
{
  [self setStr:strInput];
  [self setDate:dateInput];
  [self setX:xInput];
}

Let me point out a few things about this method. First, notice how in the definition I used the names str , date and x . However, in the implementation, I used the names strInput , dateInput and xInput . The first thing to understand is that you can do this. The reason for doing so, is that in the class where setStr() is defined, I have instance variables with the names str , date and x . If I didn’t change the names in the actual implementation, I’d get a compiler warning that a local declaration hides an instance variable.

In this code example, the simplest thing to do is to change the variable names in the method to make it obvious what variables are referring to what. This may not be the best naming scheme for your applications, however, I wanted to point out the flexibility as to how you define and implement methods and their arguments. Obviously, do what makes the most sense for your specific needs and at the same time, results in the most readable code.

Also, note that this version of setStr() does nothing more than send a message as follows: the receiver is current object instance (self), the message is a setter method and the argument to each message is the appropriate parameter passed in to setStr() .

Using the format/syntax of Objective-C takes some getting used to. However, once you do, you’ll find that it’s easy to read code that has had some thought put into the names of message and the parameters.

Variable Number of Arguments
The last topic is creating messages with a variable number of arguments. Let’s start with the interface definition of a method that accepts a variable number of arguments:

-(void) printInstanceVars:(id)input, ...;

In this example, I declare on parameter that is of type ‘id’, which can represent any object. The implementation of the method looks as follows:

-(void) printInstanceVars:(id)input, ...
{
  id currentObject;
  va_list argList;
  int objectCount = 1;
 
  if (input)
  {
    NSLog(@"\n Object #%d is: %@\n", objectCount++, input);
 
    va_start(argList, input);
    while (currentObject = va_arg(argList, id))
      NSLog(@"\n Object #%d is: %@\n", objectCount++, currentObject);
    va_end(argList);
  }
}

This method will print out each argument using NSLog(). The assumption is made that the last argument will be nil. Here is how you might call the method, passing in two objects. What’s happening here is that I am sending getter messages, if you will, to the ‘ptr’ receiver. Each of these getters returns an object. Notice the nil value as the last parameter.

  [ptr printInstanceVars:[ptr str], [ptr date], nil];

Now, this example is a little contrived in that there is probably little value in passing in instance variables from an object, as I’ve done here. However, introducing more classes at this point may confuse more than help. If nothing else, hopefully you get the jist of how this works.

I haven’t come upon the case where this is necessary in an Objective-C application, however, when programming in C, this was quite handy when reading command line parameters. So,if you ever find the opportunity, now you’ll know how. And if you are into trivia, variable argument methods in Objective-C are referred to as variadic methods, go figure.

Many of the things that I’ve covered here are much better understood by looking at a real example. I’ve attached the Xcode project that I created to learn this stuff. You best bet is to download, open the project and mess around with the code.

Here is the main method of the example, so you can get an idea of how I tested each of the above examples.

int main(int argc, const char * argv[])
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  SomeClass *ptr = [[SomeClass alloc] init];
 
  // Simple message
  [ptr printInstanceVars];
 
  // Passing a single argument
  [ptr setStr:@"Testing"];
  [ptr setX:2008];
  [ptr printInstanceVars];
 
  // Nesting of messages
  [ptr setDate:[NSDate date]];
  [ptr printInstanceVars];
 
  // Passing multiple arguments
  [ptr setString:@"A new test..." andDate:[NSDate date] andInteger:99];
  [ptr printInstanceVars];
 
  // Passing variable number of argument
  [ptr printInstanceVars:[ptr str], [ptr date], nil]; 
 
  // This won't work...
//    [ptr printInstanceVars:[ptr str], [ptr date], [ptr x], nil];
  [ptr printInstanceVars:[ptr str], [ptr date], [NSNumber numberWithInt:[ptr x]], nil];
 
  [ptr release];
  [pool drain];
  return 0;
}

Download the Xcode Project
Download the Xcode project and take some time to tinker.

Once you’ve got a good handle on the overall application, look at line 27 above. Make any sense? Here’s the deal: the variable length method is expecting objects to be passed in. The code in line 26 will generate a runtime error given the message [ptr x] returns an integer (not an object). The way around this is to create an NSNumber object by sending a message to the NSNumber receiver, with the message ‘numberWithInt’ passing in as the parameter the integer returned from the getter message sent to the ‘ptr’ receiver. If all that makes sense, you’re well on your way :)

For completeness, the entire code listing and a screenshot are shown below:

// ===========================
// = SomeClass.h =
// ===========================
#import <Foundation/Foundation.h>
 
@interface SomeClass : NSObject
{
  NSString *str;
  NSDate *date;
  int x;
} 
 
// Getters
-(int) x;
-(NSString *) str;
-(NSDate *) date;
 
// Setters
-(void) setStr:(NSString *)input;
-(void) setDate:(NSDate *)input;
-(void) setX:(int)input;
-(void) setStr:(NSString *)str andDate:(NSDate *)date andInteger:(int)x;
 
// Other
-(void) printInstanceVars;
-(void) printInstanceVars:(id)input, ...;
-(void) dealloc; 
 
@end
#import "SomeClass.h"
#import <stdio.h>
 
// ================================
// = SomeClass.m =
// ================================
 
@implementation SomeClass
// =================
// = Getter methods =
// =================
-(int) x
{
  return x;
}
 
-(NSString *) str
{
  return str;
}
 
-(NSDate *) date
{
  return date;
}
 
// =================
// = Setter Methods =
// =================
-(void) setStr:(NSString *)foo
{
  [foo retain];
  [str release];
  str = foo;
}
 
-(void) setDate:(NSDate *)input
{
  [input retain];
  [date release];
  date = input;
}
 
-(void) setX:(int)input
{
  x = input;
}
 
-(void) setStr:(NSString *)strInput andDate:(NSDate *)dateInput andInteger:(int)xInput
{
  [self setStr:strInput];
  [self setDate:dateInput];
  [self setX:xInput];
}
 
// ================================
// = Print the instance vars =
// ================================
-(void) printInstanceVars
{
  // Use the getter method of the ’self’ object to print object instance variables
  //  NSLog(@"\n x: %d\n str: %@\n date: %@\n", [self x], [self str], [self date]);
 
  // The class can directly access the instance variables (versus calling message as above)
  NSLog(@"\n x: %d\n str: %@\n date: %@\n", x, str, date);
}
 
-(void) printInstanceVars:(id)input, ...
{
  id currentObject;
  va_list argList;
  int objectCount = 1;
 
  if (input)
  {
    NSLog(@"\n Object #%d is: %@\n", objectCount++, input);
 
    va_start(argList, input);
    while (currentObject = va_arg(argList, id))
      NSLog(@"\n Object #%d is: %@\n", objectCount++, currentObject);
    va_end(argList);
  }
}
 
// ====================================
// = Dealloc all object instance vars =
// ====================================
 
-(void) dealloc
{
  // No release needed of the integer instance variable ‘x’
  [str release];
  [date release];
  [super dealloc];
}
@end
// ===========================
// = Messaging.m =
// ===========================
#import <Foundation/Foundation.h>
#import "SomeClass.h"
 
int main(int argc, const char * argv[])
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  SomeClass *ptr = [[SomeClass alloc] init];
 
  // Simple message
  [ptr printInstanceVars];
 
  // Passing a single argument
  [ptr setStr:@"Testing"];
  [ptr setX:2008];
  [ptr printInstanceVars];
 
  // Nesting of messages
  [ptr setDate:[NSDate date]];
  [ptr printInstanceVars];
 
  // Passing multiple arguments
  [ptr setStr:@"A new test..." andDate:[NSDate date] andInteger:99];
  [ptr printInstanceVars];
 
  // Passing variable number of argument
  [ptr printInstanceVars:[ptr str], [ptr date], nil]; 
 
  // This won't work...
  //    [ptr printInstanceVars:[ptr str], [ptr date], [ptr x], nil];
  [ptr printInstanceVars:[ptr str], [ptr date], [NSNumber numberWithInt:[ptr x]], nil];
 
  [ptr release];
  [pool drain];
  return 0;
}

Note: This post is the start of an on-going series for developers who are interested in learning to write applications for the iPhone. The entire series can be found here: iPhone Developer .

One of the first topics to cover when learning to develop native iPhone applications is how to code in Objective-C. Apple offers the Objective C Reference , a good resource, however, the best way to learn is by writing code. I took to Xcode to write a few simple examples, you’ll find the code below. At the end of this post I also include a link to download the Xcode project I was working with.

There are two aspects to a class, the interface and the implementation, both of which I recommend you store in separate files (although this is not a requirement).

The interface looks as follows:

@interface NameOfClass : NameOfSuperclass
{
  instance variables here...
}
class methods
instance methods
@end

The interface for my example:

// ===========================
// = Interface for SomeClass =
// ===========================
 
@interface SomeClass : NSObject
{
  NSString *str;
  NSDate *date;
  int x;
} 
 
// Getters
-(int) x;
-(NSString *) str;
-(NSDate *) date;
 
// Setters
-(void )setX:(int) input;
-(void) setStr:(NSString *)input;
-(void) setDate:(NSDate *)input;
 
// Other
-(void) printInstanceVars;
-(void) dealloc;
@end

A good coding practice is to save the implementation definition in a file with a name that matches the class name, with an extension of .h (for exampe: SomeClass.h).

This class is inherited from NSObject, the uber object. The class has three instance variables, two that point to other objects, one that references an integer variable. Take note of the getter methods: in Objective-C there is typically no ‘get’ in the front of the method name (in Java this might look like getX or getStr). Second, it should be obvious, that an instance variable can have the same name as a method, as it generally does with a getter. The ‘-’ in the front of the definition, signifies that the method is an instance method. We use a ‘+’ to define a class method (more on class methods in a future post).

One important thing to point out is the format used when declaring methods. For example, setStr() is defined as -(void)setStr: (NSString *) input ; This is translated to, the method setStr is an instance method (given the ‘-’) that returns a void type. The method takes one argument, that is a pointer to an NSString object, the name assigned to the parameter is ‘input’. The reason for the name will become more apparent when you see the implementation of the method below.

The format for the implementation of a class looks as follows:

@implementation NameOfClass : NameOfSuperclass
{
  instance variables here...
}
class methods
instance methods
@end

Here is how the implementation for the above class looks:

#import "SomeClass.h"
#import <stdio.h>
 
// ================================
// = Implementation for SomeClass =
// ================================
 
@implementation SomeClass
// =================
// = Getter methods =
// =================
- (int) x
{
  return x;
}
 
- (NSString *) str
{
  return str;
}
 
- (NSDate *) date
{
  return date;
}
 
// =================
// = Setter Methods =
// =================
- (void) setX:(int)input
{
  x = input;
}
 
- (void) setStr:(NSString *)input
{
  [input retain];
  [str release];
  str = input;
}
 
- (void) setDate:(NSDate *)input
{
  [input retain];
  [date release];
  date = input;
}
 
// ================================
// = Print the instance vars =
// ================================
 
-(void) printInstanceVars
{
  // Use the getter method of the 'self' object to print object instance variables
//  NSLog(@"\n x: %d\n str: %@\n date: %@\n", [self x], [self str], [self date]);
 
  // The class can directly access the instance variables (versus calling message as above)
  NSLog(@"\n x: %d\n str: %@\n date: %@\n", x, str, date);
}
 
// ====================================
// = Dealloc all object instance vars =
// ====================================
 
-(void) dealloc
{
  // No release needed of the integer instance variable 'x'
  [str release];
  [date release];
  [super dealloc];
}
@end

Other than learning the syntax of Objective-C, if you are familiar with OO development, most of this should be pretty clear.

A couple of things to point out:

  • The preferred file name for the implementation is the class name with a .m extension, in this example: SomeClass.m
  • Notice how this file imports “SomeClass.h” to read the class definition. If you are familiar with C, this is analgous to the #include directive. The benefit of #import is that the compiler will do the work for you to verify that the include file is only read once. If you’ve done any amount of coding in C, you’ll appreciate this convenience, if not, you won’t understand how nice a feature this is.
  • Within an instance method, all instance variables are within scope. For example, notice how the getter and setter methods refer to the instance variables.
  • Notice in printInstanceVars() method that there are two means to access the instance variables. You can use the ‘self’ object an send a message to the getter method (more on objects and messages in the next post), or you can directly access the instance variables.
  • If instance variables are pointers to objects, as are ‘str’ and ‘date’, it’s your responsibility as the developer to free the memory for those objects. The dealloc method is where you do this work. More on that to come…

To complete the example, the code that follows declares an instance of the SomeClass object, and uses the setter/getter methods to print the instance variables to the console.

#import <Foundation/Foundation.h>
#import "SomeClass.h"
 
int main(int argc, const char * argv[])
{
  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  SomeClass *ptr = [[SomeClass alloc] init];
 
  [ptr setX:99];
  [ptr printInstanceVars];
 
  [ptr setStr:@"Testing"];
  [ptr printInstanceVars];
 
  [ptr setDate:[NSDate date]];
  [ptr printInstanceVars];
 
  [ptr release];
  [pool drain];
  return 0;
 
}

A few comments on the above code:

  • Notice this file imports the SomeClass.h interface file.
  • Like working with C, main() is the function that gets everything started.
  • ‘ptr’ is a reference to an object of the SomeClass class.
  • Calling instance methods of an object follows this form: [object message:parameters]

A screenshot of the output from within Xcode of this example is below:

Creating Classes

I recommend you download the Xcode project and give it a go.

Let’s go with that for today. In the next post I’ll talk further about this simple example, including instantiation of classes, sending messages to methods and freeing memory of the instance variables.