Saturday, January 12, 2008

Objective-C using the Cocoa Framework - Part 1

Having picked up an iMac this past Christmas, I've been eager to dive into the opposing world of Mac development. I spend the majority of my time in the workplace developing using C# with the .NET framework.

I spent some time first poking around the net, looking for the best free integrated development environments (IDE) I could find for the Mac OS X Leopard platform. Before you say it, yes yes, there's always vi(m), emacs, pico, etc. While I am a fairly large proponent of vim, I was still curious what else was out there. I took a look around the XCode IDE and was thoroughly impressed with the apparent plethora of project types that could be crafted, however I soon realized I needed to resort to simpler editors first if I really wanted to "understand" some of the new languages and frameworks before letting an IDE do all the mysterious work for me behind the scenes. After digging around further I came across Smultron. Great little light-weight app that suits my needs just perfectly for coding.

For those coming from the .NET arena, wanting to sample the goods on this side of the fence, let me present you with my little analogy that helped me keep things straight. C# is to .NET as Objective-C is to Cocoa. We are dealing with languages and frameworks containing lots of useful libraries.

While this example isn't completely original, I have made sufficient enough changes and additions to warrant considering this equally informative to that of other beginner examples of the language and framework. I make no claims to be an expert with Objective-C nor the Cocoa framework, so there may be more efficient ways to perform certain tasks.

We're going to deal with a simple "Fractions" example from your most basic element of math. Say we wanted to craft our very own Fraction object.

Fraction.h
#import <Foundation/NSObject.h>

@interface Fraction: NSObject
{
    int numerator;
    int denominator;
}

-(void) print;
-(void) set_Numerator: (int) n Denominator: (int) d;
-(int) get_Numerator;
-(int) get_Denominator;
@end
Fraction.m
#import <stdio.h>
#import "Fraction.h"

@implementation Fraction
// ------------------------------------------------------
-(void) print 
{
    printf("%i/%i%c", numerator, denominator, '\n');
}

// ------------------------------------------------------
-(void) set_Numerator: (int) n Denominator: (int) d
{
    numerator = n;
    denominator = d;
}
// ------------------------------------------------------
-(int) get_Denominator 
{
    return denominator;
}
// ------------------------------------------------------
-(int) get_Numerator 
{
    return numerator;
}
// ------------------------------------------------------
@end
main.m
#import <stdio.h>
#import "Fraction.h"

int main(int argc, const char *argv[]) 
{
    // Allocate and initialize a Fraction object for use
    Fraction *fraction1 = [[Fraction alloc] init];

    // Call our set_Numerator:Denominator function, passing both parameters
    [fraction1 set_Numerator:3 Denominator:4];
    
    // Display our results
    printf("Our Numerator: %i%c", [fraction1 get_Numerator], '\n');
    printf("Our Denominator: %i%c", [fraction1 get_Denominator], '\n');
    printf("Our Complete Fraction: ");
    [fraction1 print];

    // Release all of our claimed memory
    [fraction1 release];
}
The first thing to point out here is that the implementation files for Objective-C end in ".m" rather than ".c", as you might expect. With that being said, if you have a background in C/C++, this basic structure will look very familiar - a header file depicting the API interface, an implementation file depicting the actual code for each method/function for that class, and a main driver file for controlling the flow of our program.

An additional difference I immediately noticed with the language was the numerous instances of "[..]" notation. This is basically the way method/function calls are made in Objective-C, however they are referred to more as "sending messages". You'll notice I provided a couple different examples above, some calling functions without passing any parameters (print) and other calls passing multiple parameters (set_Numerator:Denominator).

You may be asking yourself about now, okay great, I have the complete source to get me started on a simple example, but since you didn't use XCode, how on earth do I compile this thing? Is it just like C/C++? My answer, pretty darn close! After some trial and error, here's the magic command I use for compiling:
gcc -x objective-c -framework Foundation -lobjc main.m Fraction.m
If all goes well, you should see output precisely like this (including the line to execute the program):
$ ./a.out
Our Numerator: 3
Our Denominator: 4
Our Complete Fraction: 3/4
I plan on creating a gradually more complex series of examples over time, so stay tuned!

1 comments:

Howard said...

Just wanted to point out a slight error in your example here. Cocoa is a framework (as you note) that sits on top of Obj-C for Mac OS X. So when one wishes to learn Cocoa without any prior Obj-C knowledge, it is best to learn Obj-C.
In my experience, and in many other peoples that I have heard, Obj-C is a difficult language to learn. Oddly, not because it is difficult, but because it is very simplistic. Or at least strives to be.
The example code for fractions you display here is actually a direct implementation of Objective-C, not of Cocoa, nor of any of the NeXT frameworks either.

On learning Cocoa Programming, I would suggest learning some basic C (Im speaking to your readers here, not necessarily you) before taking the plunge into Objective-C. Then as you progress, learn the basic syntax and Objective-Oriented stuff of Objective-C, and once you have a OOP mindset, step into the NeXT frameworks. Keep in mind that this is not Cocoa. There are many things you can do inside the NS prefixed libraries that do not require Cocoa.

And once you understand the legacy of the language, feel free to jump inside Cocoa.