A First Look at Objective-C

Simply put, Objective-C is Object C, hence the name. You could program in Objective-C and not use one single thing that you would not in C. But that would be a waste of the language. Objective C uses everything in C, and then adds some language syntax to make it more Object Oriented. This tutorial will assume that you already know what Object Oriented Programming is, and that you are fluent in C (you don't have to be an expert, but I am not going to teach you what you should already know).

I must also recommend now that you do not stop at reading this article, because it is far from the definitive source on Objective-C (ObjC). There are several better, more complete texts on the Internet that you can find to learn this language. I have some of those linked from my website at members.xoom.com/jik_ you should maybe begin your search there.

ObjC, like any other OOP language, revolves around Objects, so lets show you how to make one. In ObjC there are two parts to an object. It has an inter- face, which is the external view of the object. And it has its implementation, which are its internal workings. To put it another way, there is what the outside world sees, and then there is what it doesn't see. This will make more sense in time.


The Interface

In ObjC, the interface is usually in a header file (.h like usual) of its own, but it doesn't have to be. You can put the interface in the same file as the implementation, or you can put several interfaces together, but each interface is different, and you must be aware of this or you will suffer. I will describe an interface as if it were a single one inside of its own header file.

To begin with, you must import the interface of this Object's superclass. You do this with the preprocessor symbol "#import" which uses the same syntax as "#include". In fact, the only difference between the two is #import will check to make sure the file is only included once. Some people choose to use #include, which is perfectly legal, but ObjC is defined to use #import, you may want to take this into account and protect your interface files for #includes. If you are using gcc (or egcs or whatever) as your compiler, you will want to use the switch -Wno-import or gcc will lecture you endlessly about using import instead of include.

So, here is the first line of code for a new class whose superclass is Object, which is usually the Godhead of all classes.

#import	<objc/Object.h> /* gcc runtime lib's Object */

Now, if you plan on using any references to any other classes, you either need to import their header files, or better yet, use the @class remark to declare that symbol is a class of some kind. The interface doesn't really need to know anything about what the class is or does, so importing its interface is rather pointless, lets use @class.

@class String;  // Simple no?

By the way, ObjC uses both "//" and "/**/" style comments which I find nice sometimes.

Well, now we are prepared to let the world know what kind of object to expect so lets declare it. First we need to say that we ARE declaring a new class, and while we are at it, define the new class's superclass.

@interface NewClass : Object // new class on left, super on right.

No, I did not forget a ';', that is exactly how it is done.

Now we declare instance variables, whether they be private or not (I happen to think privates shouldn't be visible, but its what it is :P) We do that inside of a pair of '{' '}' like we would a C structure.

{
@public
	int	aValue;
@protected // visible only by subclasses (default)
	int	value2;
@private // invisible
	int	mrInvisible;
}

That done we put method prototypes. Methods cannot be anything but public, though if I feel like it I may show you a workaround that will generate compiler warnings if you access a private method.

Methods are either 'class' (some call them 'factory') or 'instance'. Class methods are only accessible to a class object, and instance of course to instances. Or, for example, after I declare a variable that will hold an instance, but before I can use it, I must use a class method to create an instance to be pointed to by that variable before I can call any of its instance methods. Once I do, I can not access any of its class methods, only instance methods until I deallocate the object instance.

To describe a method you first put a '+' or '-' depending on whether it is a class or instance (respectably) method. Then, in '(' ')' you put the type that it will return, unless your returning 'id' which is a general type meaning "any object". Then, if your method takes arguments you put a ':' followed by the type in '('s and the variable name. You continue to do that until ending in ';' Also though, after the first argument you can put words in before the next ':'. These must not have any spaces in them.

Since you're likely very confused, lets look at a class and instance method.

+createWith:(int)value;  // easy enough
-(void)say:(String*)what to:(String*)name;  // the first argument is 'what',
					// the to is part of the method's name.

Using words inside of the argument structure can make the method make more sense when spoken. Like if I were to speak out the second method when I used it, it would sound like "say 'Hello' to jik-" instead of "say 'Hello', jik-".

Variable length argument lists use the same syntax as they do in C:

-(void)doStuff: (id)format,...;

Finally, when we are done declaring the object we need to tell the compiler we are finally finished by saying:

@end

Everything from here on is considered to be not of this object. You can continue to declare objects, use typedefs or any other C language stuff you would put into a header.


A Small Blurb on Names

Method names will be everything but the +/-, types, and arguments. For instance, the method "-(void)say:(String*)what to:(String*)name" will be "say:to:" internally. If you have applied the gdb ObjC patch, then this is also how you refer to methods by name.

Also, you must keep in mind that ObjC is most often processed into C and passed to the C compiler. Names get changed so you must be aware of this and not do things that might trick the compiler.....like

-roll_d:(int)sides;
-roll:(int)count d:(int)sides;

In this case, both methods will get turned into the following C function by gcc

__i_ClassName_roll_d_()

This happened to me, so believe me, you must be careful, if I were you I would not use the '_' in the middle of any method names. The start should(TM) be ok.


Messaging

Since you use messages quite a lot in the implementation, we must first discuss what they are and how to express them in syntax. A message is simply the invocation of one of an objects methods. We call them messages in OOP because it is like sending a message to an object telling it to do something. You express a message by saying the object's name, followed by the method you wish it to perform with any arguments you are sending it, enclosed within '[' ']'.

For example:

[object jumpAround];
or
[object jump:forward];

"object" can either be a class or an instance of some class. Usually a class has a capital as its first character, and instance a lower case. If "object" is a class then you can only ask it to perform class methods....and visa versa.

For example, to create a new instance of "Object" we would use...

[Object alloc];

"alloc" being a class method which allocates memory for the new object. This does not make the object useful because none of its instance variables were initialized...to do that we call "init"...so, the whole thing would go....

id object = [Object alloc];
[object init];

You can also use the return of a message as any part of another message, provided it returns the correct type. Since the 'alloc' message returns type 'id' we can use its return as the object for a new message. This is why it is often better to return 'id' instead of void as void cannot be used for anything. If your method is finished, it is better to return 'self' which is the variable for 'this current object', unless you want it not to be used as an argument or object in a message....then use void. A good place for void is in deallocation methods, a bad place is in allocation.

So, if we were to use that ability to do the 'alloc' and 'init' in one line we would do:

id object = [[Object alloc] init];

But of course we have to also be sure that init is going to return 'id' as well or we won't be able to make further use of the variable 'object'.

Messages get evaluated from the furthest in to the furthest out. If you use a message as some part of another message, all of the internal messages will be evaluated and returned before the outside one will be evaluated. The eventual return will be of the last message evaluated, not any of the internal messages that were used to feed the big one.


The Implementation

This is the part of the object that does everything. It defines the internal workings of all the object's methods, or should I say, any that are not inherited. Implementation files have the postfix '.m

To begin with, you need to import the class headers for this and all classes which are going to be used in this object. As always, you can also do any extra defines, typedefs, or anything else you might do in C at the top of a source file.

After your done with all the preparations, you tell the compiler that you're defining the implementation of a new object. You do this in somewhat the same way as the interface, but now you don't need to say what the superclass is unless you didn't create an interface for this object (which IS ok to do). Course, you CAN say what the super is again if you want to, nothing says that you can't. You do it in the same way as with an interface.

@implementation NewClass

You don't add any instance variables here, so we don't put that part in the implementation. What we do now is define any new method, and any inherited methods we want to override. The syntax to do this is sort of a cross between the method declarations in the interface, and C functions.

Here is an example of a short method definition:

-sayHello
{
	printf("Hello world!\n");
	return self;
}

And one which takes arguments and uses messaging:

-say:(String*)what
{
	printf("%s\n", [what cString]);
	return self;
}

You end an implementation in the same way as the interface

@end


Special Methods

There are some special methods which you should be aware of when subclassing in ObjC. These can be called different things in different APIs, but something similar is bound to be a part of any. Some methods should never be overridden under most circumstance, others can be but you need to meet certain requirements if you do so.

You should not subclass the 'alloc' method. This method does special things to allocate the storage space for the new instance. It should be defined in Object in such a way as it will allocate the correct space for whatever class your creating an instance of. If you override this method your class will most likely not function correctly.

If the library your using uses a reference counting scheme, for instance libFoundation which uses autorelease pools for object cleanup, you should not override the 'release', 'autorelease', and 'retain' methods. These methods do special things to keep track of the references to this object. Changing any of these methods can make the entire scheme fall apart.

The 'init' method can be overriden, but you have to make sure you call the superclass's 'init' before doing anything or variables can be left uninitialized. ALWAYS put '[super init];' as the first line in an overridden 'init'.

In 'dealloc' or 'free', whichever the library your using uses, also needs to call super, but at the END, not the beginning of the method. Simply using the line 'return [super dealloc];' at the end of the method will be sufficient to do all the necessary cleanup of the super classes.


Non-standardization Issues

ObjC has a curse that comes with it. There is absolutely no standard for it that names off all the language abilities or runtime support. Every single ObjC compiler is non-compatible with the rest. This means you pretty much have to target a specific compiler because they are so drastically different that you can't usually use anything like #ifdef to successfully write cross compiler source.

Not only are the runtime libraries totally different, but the difference extends to language. For instance, there are other types in ObjC such as Categories and Protocols which are not in all implementations. Some will have them, some will not. I am sure this goes much deeper, but this is the surface of the problem.

You must be aware of this when making the choice of compiler. Some compilers, like the POC, are cross platform capable, but have missing pieces to the language. Some are more complete, yet still lack some essential parts, for instance, gcc has a pretty complete ObjC implementation, but lacks support for unloading modules (ObjC is supposed to have the ability to add and remove various parts at runtime, gcc can load them, but not remove).

There are some relativities between some compilers. Some like Stepstone and POC follow more along the lines of the language's original implementation, written by Brad Cox. Others, like gcc, follow more of what NeXT came up with. All of them are different however, do not depend on being able to compile source written for one on another without rewriting a good portion, if it is even possible.

With that in mind, I will introduce you to some of the concepts which are less portable. So far, everything I have told you about is in every implementation of ObjC. Now we get into areas which are less standard.


New Types

ObjC has some new types which I should mention about now. Some of these types may have different names, some may be missing. You must find out what your compiler has or doesn't have.

BOOL is a Boolean type which can either be YES or NO.  NO is 0, YES is non-0.
STR is a char*.
IOD is a FILE*.
id is a generic representation of any ObjC object..
SEL is a way to represent a method as a variable.  You can ask objects to
	perform the method which the SEL represents.  You create a SEL with
	@selector(methodName).  'methodName' is the ObjC representation of the
	method, for instance 'say:to:' as I mentioned above.
IMP represents a method as a C function pointer, sort of.  This can be used when
	you wish to save the time it takes to do message lookup as the IMP is
	a direct link to the method.  Use in fast loops and such.

That should get you going ok....like I said, this is not a definitive source on Objc.


Categories

Categories are a way to extend an objects abilities. You can add new methods to the object, but you cannot add new instance variables. The new methods are considered a part of the class the extend, subclasses will inherit all of the new abilities. You can also override methods in the class by creating a category which does this. If you have 2 categories which override the methods of one class, it is undefined which one will replace the old.

Category syntax is similar to class syntax. They have both interfaces and implementations. There is a slight difference however. The beginning lines in a category are like so:

@interface ClassName (CatagoryName)
@implementation ClassName (CatagoryName)

ClassName is the name of the class you're extending and CatagoryName is a way to identify the category. Categories have access to all instance variables of the class the extend.

The rest of the syntax is the same, you declare method in the interface, define them in the implementation, end end with '@end'.

You can use categories to make mock private methods. Put the category interface above the class's implementation in the same file. Put any methods you want to be private in this category. Create the object's implementation, then, at the bottom of the file, put the category's implementation. This will hide the methods from the rest of the world in such a way that the compiler will generate warnings if you access these methods. It will NOT keep it from happening during runtime, it will only tell you when you compile. There is no way to keep methods from being accessed in ObjC.


Protocols

Protocols, like the name hints, are definitions of behavior which a group of classes can conform to. Protocols have no interface or implementation, but they more resemble an interface. You don't add new instance variables, nor do you add new methods or define the internal workings of any method. All a protocol does is to define a set of methods which a class must contain in order to conform to this the protocol.

Protocols come into good use when you're making use of ObjC's dynamic typing ability. ObjC has dynamic runtime typing just like Java. This is one of the things it has over C++ which only has dynamic 'compile time' support.

Say you are creating a method which can accept any object. You are going to have to find out if the object is going to be able to respond to the message your about to send it, or you could send a message the object doesn't understand. This will cause problems to say the least. If you use a protocol, you can make sure it responds to the many messages you're about to send it, if your only sending one message there are other ways to check....I leave that to your research.

Also, in the above situation, you could make the protocol a requirement for the argument you're expecting. I will show you how to do all of this stuff now.

To define a new protocol, start with:

@protocol ProtocolName

followed by any number of method declarations, using the same syntax that you do in interfaces. End the protocol with '@end'.

Now, in order to conform to a protocol, you declare your intent in the interface of the new object your creating. Then you must define all the methods that are in the protocol, in the implementation of a conforming object.

@interface NewObject : Object <ProtocolName

The above tells the compiler that this is NewObject, who's superclass is object and that it conforms to the 'ProtocolName' protocol.

To find out if an object conforms to a specific protocol, use the 'conformsTo:' method.

[object conformsTo:@protocol(ProtocolName)];

This will return YES or NO depending on weather the object conforms.

To ask for an argument which conforms to a certain protocol, declare the method like:

-method:(id )argument;

You can also return an object which will conform to a protocol.

-(id )method;


In Conclusion

Well, that is a quick and dirty introduction to ObjC, you will still need to go on to other sources of information about the language in order to learn it. My website has a few links, besides that...do a web search or ask around.

I'll leave you with a short and minimal example which will compile with gcc.


Noah Roberts (jik)
I hereby grant, free of charge, the right to copy and redistribute this work whole in any form or format, as long as this copyright notice appears intact somewhere on or about the copy (it must be obviously available to the reader of the copy, from the copy). You may edit this document to fix spelling or grammatical errors, but you must not modify it's content in any other way. If you object to this license you must contact me for permission to copy this document.

Last modified: Tue Mar 16 21:25:46 PST 1999
Created with XEmacs