Your First Objective-C Program

Let’s write your first Objective-C Program.  It’s not going to be much different from you first C program, but we’ll introduce creating a class and creating an instance of that class and sending that instance a message.  We’ll go over briefly what is entailed with reference counting which you will research in detail from the Objective-C 2.0 Programming Language.  You should read the Configuring XCode tutorial before going over this.

Use the Organizer to add a new file to the ObjC folder called first.m.  Note the .m extension instead of the .c extension. Copy and paste the following code into the new file.

#import <Foundation/Foundation.h>
 
@interface MyClass : NSObject
{
  float myFloat;
}
 
- (void) hello;
 
@end
 
@implementation MyClass
 
- (id) init
{
  self = [super init];
  if(self != nil)
  {
    myFloat = 5.0;
  }
  return self;
}
 
- (void) hello
{
  NSLog(@"Hello, I'm your first Objective-C program!");
}
 
- (void) dealloc
{
  // release any retained objects here.
  [super dealloc];
}
 
@end
 
int main(int argc, char**argv)
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
  // allocate an instance
  MyClass *instance = [[MyClass alloc] init];
  [instance hello];
 
  [pool release];
 
  return 0;
}

Wow. That’s a lot of new stuff. That’s OK, let’s break it down part by part. Here we are defining a new Objective-C class and then in main we are creating a instance and sending it the message hello.  Before we go any further though, you should attempt to compile it.  I’m not going to go over the bits from the earlier tutorial.  You should make a new Build Action shell script that does the following:

gcc -g -Wall -framework Foundation -o first first.m

Notice that you have a new flag -framework. This tells GCC that you want to link your code against Apple’s Foundation framework. This where all of Apple’s fancy classes are defined, like NSArray, NSDictionary, NSView (note NS stand for NeXTStep).  Linking just means that this your code references functionality that is part of the system and not a part of your program.

You should now add a new Run Action shell script that runs your program. Make sure that you get the expected output in XCode’s Console before moving forward.

Take another look at the code. If you’ve created objects in Java before this should be conceptually familiar. Before reading the following take some time to guess at what the different parts might do. How is this different from what you’ve seen before in Java or some other programming language (PHP, Python, Ruby, JavaScript, C++, etc)? One thing that might pop out is that there’s return types just like Java or C++. There’s also a string in there with a funny @ character. Comments look pretty much how they look in Java, and #import seems to have a functionality similar to #include in C.

Let’s dissect the first part:

@interface MyClass : NSObject
{
  float aFloat;
}
 
- (void) hello;
 
@end

Here you are defining the interface to your class. The concept of interface is not that dissimilar from the meaning in the physical world. A steering wheel is the interface to a car. You could climb into the engine and try to drive the car, but that probably wouldn’t be very productive or safe. Pretty much the same for programming. The interface of an Objective-C class declares how it interacts with the world. People can talk to your object through this interface. In fact it’s probably the only way someone should talk to an instance of your class. If they don’t they are attempting to mess around with the insides of your object, that is, its implementation.

Here we are defining a new class called MyClass, it inherits functionality from NSObject. You might make classes that inherit from other classes (especially NSViews or UIViews), but NSObject is the root class. In fact you can’t really have an Objective-C program without it. Ok, that’s not totally true, you could, but this object wouldn’t function very well because NSObject “knows about” Apple’s Objective-C runtime.  Your object would need to know quite a bit about Apple’s runtime for it to “act the right way.” For the curious looking for a challenge I highly recommend reading the documentation.  This documentation explains the guts of how Objective-C works.  It is not black magic.  It makes sense, and will be useful to anyone expecting to understand why Objective-C is the way it is.

MyClass defines a single instance variable, myFloat.  It has the C type float which you should be familiar with from your C readings.  Instance variables are private to a class.  You can actually access this (though it seems like Apple might ship a version of Objective-C where this is not possible anymore, possibly Snow Leopard).  If you think you know something about structs, I highly recommend you take a second to figure this out.

The interface also defines a single method.  This method returns nothing and takes no parameters.  Methods are like functions except they are associated with a class.  You can actually call methods by themselves as C functions but you’ll need to read the runtime documentation to figure out how.  Note the syntax for defining a interface, no much to say about except that you should memorize it.

On to the implementation part:

@implementation MyClass
 
- (id) init
{
  self = [super init];
  if(self != nil)
  {
    aFloat = 5.0;
  }
  return self;
}
 
- (void) hello
{
  NSLog(@"Hello, I'm your first Objective-C program!");
}
 
- (void) dealloc
{
  // release any retained objects here.
  [super dealloc];
}
 
@end

You can think of the interface and the implementation as being analagous to the header and source file of a C program. The header file in C defines the functions which can be used. Often C programmers will declare structs and functions for operating on them in the header file. The actual functions are implemented the source file (and often many many more functions which aren’t meant to be called on directly, this describes encapsulation). Here we have definition for three methods, that’s two more than what defined in our interface! What gives?

init and dealloc are special methods. In Objective-C you allocate objects, that is, you tell the runtime environment you want to allocate memory for an object and receive a pointer for it. Objects are pretty useless unless they are initialized. When you explicitly allocate an object you need to instantiate it. There are APIs in Cocoa that return pre-initialized objects, but we’ll get into that later.

Usually when you initialize an object, you initialize the values of it’s instance variables. Here you can see we are setting the value of myFloat to 5.0. Note that there’s also this strange variable called self. self is a special variable that refers to instance that is being operated on. This is analogous to this in Java. You should always return the newly instantiated object from an initializer. Note that the return type is id. id is the most generic type declaring that the value is an object. This should make sense if you read about C types and type declarations, there’s nothing new going on here.

On to the hello method. It’s return type is void. It calls a C function called NSLog. Surprise, you can mix C and Objective-C together (even C++). The string has a funny character in front of it, that ’s because it’s not a regular C string. It’s shorthand for NSString, the base string object in Cocoa. String manipulation sucks in C as you probably discovered working on your assignments from last week. NSString bring modern string manipulation to Objective-C. You can use type format specifiers in NSLogs just as you would with C’s printf.

The last method is the dealloc method. This is analagous to C’s free function. When you dealloc an object you are essence destroying it and releasing the memory it uses so that it may re-allocated for other objects. In general the only thing you should do in dealloc is release any objects that you may have retained. This is getting into Objective-C memory management which is the heart of the assignment this week. Don’t get too distracted about this now.

Onto the last part, and then we’ll make a small modification:

int main(int argc, char**argv)
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
  // allocate an instance
  MyClass *instance = [[MyClass alloc] init];
  [instance hello];
 
  [pool release];
 
  return 0;
}

Looks similar to the hello.c file but with a couple of key differences. The big difference is this weird thing called NSAutoreleasePool. Apple realized that memory management is hard and that having to explicitly malloc/free every single thing you want to use is tedious and error prone. To solve this they implemented reference counting. Reference counting your own objects is not really much less error prone then malloc/free. You’ll find this out soon enough. However, there is one place where it pays big dividends.

Autorelease pools work great for dealing with objects from Apple’s core APIs. As you learn the API, you will find that you rarely, if ever, explicitly alloc/dealloc a string or a date. Autorelease pools take care of this so well that it is almost like a poor man’s garbage collection system. Objective-C’s memory management model is one of the hardest things to understand about Objective-C and it’s also the source of many, many errors. You should play around with reference counting as much as possible. We’ll get into even more detail next week. For now let’s make a little change to this program.

A common paradigm in Objective-C is the setter/getters. Direct instance variable access is frowned upon for many good reasons. Let’s definite a getter and setter for myFloat. Copy and paste the following into the implementation section of the code.

- (void) setMyFloat:(float)val
{
  myFloat = val;
}
 
- (float)myFloat
{
  return myFloat;
}

And make main look like the following:

int main(int argc, char**argv)
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
  // allocate an instance
  MyClass *instance = [[MyClass alloc] init];
  [instance hello];
 
  [instance setMyFloat: 10.0f];
  NSLog(@"new value is %f", [instance myFloat]);
 
  [pool release];
 
  return 0;
}

Build and Run this code. You should see the following output:

objc1

You’ve just mutated your first object. By mutate, I mean that you changed it’s internal state. Setting primitive values for variables is a fairly basic thing. Things only start getting interesting when you start assigning objects to other objects, which is covered in the assignment.  When doing iPhone development managing objects will take up the bulk of your programming.