Beginners Guide to Objective-C Programming

Permission to use, copy, modify and distribute the Beginners Guide to Objective-C Programming and its accompanying documentation for any purpose and without fee is hereby granted in perpetuity, provided that the above copyright notice and this paragraph appear in all copies.

The copyright holders make no representation about the suitability of this Guide for any purpose. It is provided "as is" without expressed or implied warranty.


Table of Contents
Preface
1. About this guide
What you need before you start
Credits and links
2. My first steps
Hello, World!
Commenting the code
Small is beautiful
3. Inside objects
Data
Functions
C more ...
4. Getting help
Reading man-pages
Reading .h files
5. Keep It Simple, Stupid
Object.h
Protocol.h
List of Tables
2-1. source file extensions
3-1. C standard types
3-2. Derivative types
3-3. Objective-C data types
3-4. Decimal to binary
3-5. Creating -1
3-6. Creating -5
3-7. Arithmetic operators
3-8. Relational operators
3-9. Logical operators
3-10. More short hand notations

Preface

What Have They Done To My Song Ma
 

Look what they done to my song ma
look what they done to my song
well it's the only thing
that I could do half right and it's turning out all wrong ma
look what they done to my song

 
--Melanie Safka 

Objective-C is an object oriented programming language. It is not a standardized language, that is, there is no official standard that describes Objective-C. Brad J. Cox developed the original Objective-C language, by adding SmallTalk-80 extensions to C.

Objective-C is ANSI C with a relatively small set of smalltalk-like object oriented syntax grafted on to it. It is considered to be the most dynamic of the C based OO languages.

The Objective-C runtime is part of the GNU C compiler (gcc). And also part of the NeXT and Mac OS X compilers.

Dennis Gladding wrote the first GNU version in 1992, shortly followed by the second version by Richard Stallman. In 1993 the next version appeared written by Kresten Thorup who also used this version for the actual NeXT implementation. Later versions where maintained by Ovidiu Predescu and currently (2001) Stan Shebs of Apple Computer Inc. is the responsible person.

Objective-C highligts


Chapter 1. About this guide

I wish I could find a good book to live in

Almost every document I have found on Objective-C programming assumes you already know about C programming or object oriented programming. And if you are like me, a non-programmer that once in a while writes a shell script, that is frustrating. So on a nice and shiny friday afternoon I decided to write a book about Objective-C programming, for the non-programmer. A book that I would like to have myself.

Objective-C is an extension to the C programming language, which makes C object oriented. This is nice, but actually not something you want to know. You want to write a program that works. So this book will take the practical route. Through examples I will try to guide you, and myself, through the first steps of creating an Objective-C program.

No prior programming knowledge is assumed and references will be given to further documentation, since not everything you want to know will fit in this book. I will try to get you started, not master you in Objective-C.


What you need before you start

well if I could find a real good book

Every program you use on your computer is written in a language that humans can understand. Then it is translated to a language a computer can understand. The language you use to write programs is called a programming language and the piece that the computer understands is called a binary. The process of translating the one into the other is known as compiling. So you need a compiler to use the programs you write.

The idea about this book is is that everybody wanting to learn Objective-C should be able to do so. The tools that I use in this book should thus be available to you too. The simplest solution I could come up with is to use the Free Software Foundation tools from their GNU project. This means that I will use in every example the Free Software Foundations GNU Compiler Collection (gcc) to compile programs.

This compiler is used on many systems. Most Unix systems have gcc and also Apple Mac OS X has gcc as its default compiler.

Next to that I will assume you have the GNU make installed. On certain systems GNU make might be present as gmake. In that case substitute all make by gmake


Credits and links

I'd never have to come out and look at what they done to my song

I could not have written this book, without the enormous amount of help of just one single person: Pascal Bourguignon. When I asked a single question he wrote pages of information to help me understand C, Objective-C and even SmallTalk. Pascal invested, I guess, more or less the same amount of time in this writting as I did. For that I am very grateful and it shows the open spirit in which Open Source projects flourish.

A lot of notes on the code I received from Chris B. Vetter. I also would like to thank him for his always possitive, constructive remarks that helped make this Guide what it is.

Once you understand the basic concepts, the actual learning starts. Come out and ask questions, read online documentation and good books. A quick reference is the books and sites I used to write this document.


Chapter 2. My first steps

Look what they done to my brain ma

Hello, World!

look what they done to my brain

The C programming book, written by the inventors of C, start with a program that prints hello, world on your screen. I figured that it might be a nice start to do just that.

I will give you the code first, and then we will look at what all the parts mean.
/* Comments:
 ** Example written by Pascal Bourguignon
 ** return status change by Chris B. Vetter
 ** Added comments in empty {} section by Chris B. Vetter
 ** int main() changed to int main(void) by Dennis Leeuw
 **            from comments by Chris B. Vetter
 */

#include <objc/Object.h>

@interface Greeter:Object
{
  /* This is left empty on purpose:
  ** Normally instance variables would be declared here,
  ** but these are not used in our example.
  */
}

- (void)greet;

@end

#include <stdio.h>

@implementation Greeter

- (void)greet
{
	printf("Hello, World!\n");
}

@end

#include <stdlib.h>

int main(void)
{
	id myGreeter;
	myGreeter=[Greeter new];

	[myGreeter greet];

	[myGreeter free];
	return EXIT_SUCCESS;
}

It all looks very complex, for now just use your favourite editor and make sure you copy the program as is. Write it to disk with the name hello.m

File extensions

There are a couple of rules to the extensions of files, to make life easier. With the correct use of extensions, the compiler can easily detect what kind of language is needed. Ofcourse you could use gcc -x <language>, to tell gcc what kind of input file it is, but using the correct extension is easier. Next time you see a file, you yourself know in what kind of language it is written.

Table 2-1. source file extensions

LanguageExtensionCompiler directive
C.c-x c
Objective-C.m-x objective-c
C++.cc or .c++-x c++

Leave your editor and type on the command line:
bash-2.05a$ gcc -lobjc hello.m -o hello
This tells gcc to use Objective-C (-lobjc, or actually this makes gcc tell the linker to link-edit the program with the library libobjc.so, but you might want to forget that sentence) and to read the source from hello.m and to output a binary file called hello

You should not see any errors. If you do you probably do not have the Objective-C part of gcc installed. Please make sure you have it installed and working before you proceed.

If the command prompt returned without any messages, then you are fine. It worked and you have now your first working Objective-C program! Type on the command prompt the following, to see that I am right:
bash-2.05a$ ./hello
Hello, World!


Commenting the code

well they picked it like a chicken bone

We will dig through the program, from top to bottom to see what we have done.
/* Comments:
 ** Example written by Pascal Bourguignon
 ** return status change by Chris B. Vetter
 ** Added comments in empty {} section by Chris B. Vetter
 ** int main() changed to int main(void) by Dennis Leeuw
 **            from comments by Chris B. Vetter
 */
This section is a comments section, meaning it has nothing to do with the actual program. A compiler discards this part. Everything between /* and */ is useless to the compiler, but very useful to us, the programmers. This is for us to make notes within the source code. Like I did to document the changes I made to the original source.

Another way of commenting your source is by the use of //. This is not a container like /* and */ which comments everything between the two, but // comments everything from the double slash, until the end of line. I commented the following code with this method.

#include <objc/Object.h>  // Includes the gcc Object.h header file

Every program you will ever write uses atleast functions and variables. Functions tell a program what to do and variables hold the data with which the functions work. In object-oriented languages, variables and functions are gathered together in objects.

Objects consist of instance variables (data) that represent the state of an object, and methods (functions) that act on these variables in response to messages. One can see an object as a simple program that you can call (send a message to) to perform a simple action.

With the above paragraph I introduced a couple of the terms used in object-oriented programming. This section will try to make you familiar with the meaning of the above terms.

To make life easier you will often use functions and objects written by others. To tell the compiler that you will use a function not available in this file you use #include. A lot of documents you will read later, might tell you to use #import, but that is not used anymore. You always need to use #include.

In this example we included Object.h, which is provided by the compiler.

The fact that you needed the Objective-C part of gcc to compile the program, has to do with Object.h. The Object definition written in Object.h is the basis for all objects. It is said that Object is the root class of all classes.

Objects, Classes and instances

If we are a school for actors we have a written definition of what an actor is. From the The cambridge dictionary a description might be: "someone who pretends to be someone else while performing in a film, theatrical performance, or television or radio programme".

With the above we have defined a class. In this case everyone that fits within the above description is an actor. The oposite is also true, everyone who wants to be an actor has to perform the above definition.

Assume a girl taking a course at our school. When she finishes our school she will become an actress. Which is equal to the compiling we did. When the compiling succeeds we have created a class object, namely an actress, able to perform any role. As long as the compiling is not successful the lessons aren't finished.

But as the above definition says she will only be a true actress, when she performs, she has to perform in e.g a play. Since every play is different she has to learn a role (get specific, play related, information: instance variables). When she plays the role she has then become our object.

Our actress of course is also female, so her root class is females. And she inherits from her female root class all methods that make her female.

As with Object.h which is just the definition of an object, we also need to tell the compiler what we are going to do. We first need to define what the compiler is going to expect. For that Objective-C has the @interface/@end construction. This part is normally saved in a .h file, but I choose to first present you with the entire file. Later we will split things up.
@interface Greeter:Object
{
  /* This is left empty on purpose:
  ** Normally instance variables would be declared here,
  ** but these are not used in our example.
  */
}

- (void)greet;

@end

The first line tells the compiler that Greeter is a subclass of Object, so it inherits everything directly from the root class Object.

Inheritance

As seen above inheritance is a very powerful Objective-C functionality. With just one line, we included all methods and data from the Object class.

Then we add the method greet which makes our Greeter special. The difference between Object and Greeter is the method greet.

What we did was using the general Object class and tell the compiler that from now on everything an Object can do Greeter can do too. So Greeter is identical to Object. But that is not what we want. We want Greeter to be a special Object. That is what the - (void) greet; is about.

With the - (void) greet; we extend our Greeter object with an additional functionality. Next to all the Object methods, it now also knows the method greet.

Methods

Methods are the functionalities that an object can perform. Objects that we write have two kinds of methods: The methods that are inherited from the root class and the ones that we have added.

On our school we will educate our girl the methods of an actress, which equals to programming a class (we write the methods). When she finishes our school she is an actress. Her exam is our compiling stage.

Now that we defined our Object we can close the definition with @end.

The next section we are going to look at, is the implementation section. This will describe what our object Greeter does. Since we inherited all functions available in Object, we do not need to write them (now you must start to feel all warm and fuzzy about object oriented programming). We only need to tell the compiler the things that make our object Greeter so special:
#include <stdio.h>

@implementation Greeter

- (void)greet
{
        printf("Hello, World!\n");
}

@end

This section tells the program what to do, namely to print to our screen the words Hello, World!, followed by a new line. Remove the \n from the print-statement, recompile the code and execute. Now you know why the \n was used.

The first thing you might notice is the fact that another #include is present. Normally you would group the #includes at the beginning of your program, but I had a special reason to put it here, which I will explain in a following section, when we split up our little program.

As the inclusion of Object.h, added Object functionality to our program, so does stdio.h add the standard input/output functions. You should take for granted now that this inclusion adds the function printf which we need later.

And the last section is what makes the program work. Every program has a special function called main. Normally you are free to call your functions whatever you want, as long as you do not call them main. With main you tell the compiler: Hey you, my program starts here! The rest of this chapter will describe the main part of our little hello.m file.

#include <stdlib.h>

int main(void)
{
        id myGreeter;
	myGreeter=[Greeter new];

	[myGreeter greet];

	[myGreeter free];
	return EXIT_SUCCESS;
}

The first important things are the { and } symbols. They are called the block statements. Normally after each function a single statement is allowed. In our example the main-function you see has 5 statements, the ones ending with ;. To overcome the limitation of a single statement, we group the statements together to form a single one by enclosing them between { and }. This will in a later chapter be explained in more detail, for now it is enough to know that everything between the { and } symbols is our program, or main function.

Note that every statement you write is separated by ; (a semicolon), so one could write:
int main(void)
{ id myGreeter; myGreeter=[Greeter new]; [myGreeter greet]; [myGreeter free]; return EXIT_SUCCESS; }

But that would make our code almost unreadable. So next to the ; separator, we also like to maintain readability. The ; separator is forced on us by the programming language, the line breaks and the idents are from me. You will soon learn that a lot of people have different conventions on how to layout code. I will not bother you with that. If you like to know more on that you could read GNU Coding standards.

Another agreement is to start with your variable declaration.
id myGreeter;
defines a variable that is called myGreeter and that is an object.

Next we create our object.
myGreeter = [Greeter new];
Up until now we just defined the class object Greeter, and now we create a new instance by sending the new message to Greeter and we create the object myGreeter. The object is alive, we started it!

Messages

By sending a message to an object, we ask the object to perform one of its methods. In this case we send to our object Greeter the message to perform the method new. new is one of the methods Greeter inheritated from Object.

Another way of creating an object is by using:
myGreeter = [[Greeter alloc] init];
Which is often used in Cocoa and GNUstep programming. With this you see that you can send two messages after another to an object. Messages can be nested.

Our actress playing a role on stage, has to listen to the other players to know when and what to perform. The events happening on stage are the messages on which our actress acts.

Now that we have an operational object, we send another message to the object and that message asks the object to perform our method, namely greet.

Now that the object has done what is should do it is time to let go. By sending the new message we created the object which then of course occupies some memory space. By using free we destroy the object so that the memory can be used again.

We end the function by returning a EXIT_SUCCESS value to indicate that all went well. In Objective-C this is noted as return EXIT_SUCCESS;.

Exit status

In a lot of programs you might see return 0; when ending a program. On most systems a successful operation is indicated by 0 and a failure is reported as 1. However this is not the case on every system. For this the include file stdlib.h defines the values for success and failure through the names EXIT_SUCCESS and EXIT_FAILURE. Using these instead of 1 and 0 makes your code portable to every system.


Small is beautiful

and I think I'm half insane ma

You have seen that the a little program for just printing Hello, World! can give you a fair amount of text in you source file. To keep your programming organized and to help you in more effective reuse of your code it will help you to split the previous program in several parts.

The code of the program almost dictates where this sample should be split. The first section is the declaration of the object called the interface, the second part is the implementation of the object and the last part is the main function.

The first part we will be looking at is the interface of an object. The interface describes how our object is seen from the outside world and is described in a header file. Header files have the .h extension. In our Hello, World! example we created the Greeter object, create a file called Greeter.h with the following content:
/* Comments:
** Example written by Pascal Bourguignon
** Added comments in empty {} section by Chris B. Vetter
*/

#include <objc/Object.h>

@interface Greeter:Object
{
         /* This is left empty on purpose:
	 ** Normally instance variables would be declared here,
	 ** but these are not used in our example.
	 */
}

- (void)greet;

@end
The logic of Objective-C is that the interface of an object is defined between @interface and @end. As described earlier we included our root class, Object, and added the method greet. All other programers need to know about our object is here. There is nothing else they need.

The interface

The general definition of an interface looks like this
#include "ClassName.h"

@interface ClassName ( CategoryName )

/* method declarations */

@end

When using all kinds of small objects certain header-files like stdio.h might be included several times, which is not very economic. It would be nicer if it was only included once. To make sure that that is the case there is an construction that looks like this:
#ifndef _INCLUDED_STDIO
#define _INCLUDED_STDIO

#include <stdio.h>

#endif
What this tells the compiler is that if _INCLUDED_STDIO is not set, set it and include stdio.h. The next time it comes across a #ifndef _INCLUDED_STDIO the variable is defined and stdio.h will not be included. You should of course use the same variable name for each ifndef.

We however need to implement our object Greeter by creating the class. To be able to reuse this object we create a single file that will only hold the objects implementation. So create a file called Greeter.m with the following content:
/* Comments:
** Example written by Pascal Bourguignon
** added #include "Greeter.h" after splitting hello.m by Dennis Leeuw
*/

#include <stdio.h>
#include "Greeter.h"

@implementation Greeter

- (void)greet
{
        printf("Hello, World!\n");
}

@end
An implementation description follows the same logic as the interface it is defined between @implementation and @end.

It might get clear to you why I didn't group the #include statements in the single file hello.m program. The stdio.h is only needed by our object Greeter so it is included here, in the implementation. Also note the difference in include statements. And include statement embraced by < and > means that the .h file belongs to the system, while an inclusion with " and " means local to the directory where the Greeter.m file can be found.

The implementation

The general definition of an implementation looks like this
 
#include "CategoryName.h"

@implementation ClassName ( CategoryName )

method definitions

@end
 

And the last part of our program is the actual call to our object. This part is what makes it a program, the rest only defines our object. Here we create the main function, so let's call the file main.m and fill it with:
/* Comments:
** Example written by Pascal Bourguignon
** return status change by Chris B. Vetter
** int main() changed to int main(void) by Dennis Leeuw
**            from comments by Chris B. Vetter
** added #include "Greeter.h" after splitting hello.m by Dennis Leeuw
** added #include <stdlib.h> to create system independance for return
*/

#include "Greeter.h"
#include <stdlib.h>

int main(void)
{
        id greeter;
	greeter=[Greeter new];
		        
	[greeter greet];

	[greeter free];
	return EXIT_SUCCESS;
}

To compile this we have to do several things. First we need to create the object Greeter, then we need to create main and we then have to link them. That's quite a mouthful. Don't worry I am gonna explain it step by step for you and then tell you there is an easier way of doing things.

To translate the Greeter.m file into machine code run:
gcc -c Greeter.m
The -c option tells gcc to compile or assemble the source file, but not to link. Linking is....FIXME

The next stage is to do the same for main.m:
gcc -c main.m
Now we have two object files. Look in your directory and you will see the non-exectables Greeter.o and main.o.

What we need to do to make this function is to link the two into a real program. We don't have to do this our selfs, we can just instruct gcc to do it for us:
gcc -lobjc -o Greeter main.o Greeter.o

To avoid conflicts with hello, we created the executable with the name Greet, so type:
./Greet
And see a well known output.

That was quite some work. Why the hell should we ever wanna do this? It was much easier when everything was one single file.

For such a small project like a Hello, World! program that might be the case, but for large projects with objects that you once wrote and might like to use in other applications it is a different subject. Not needing to copy and paste code from one file to anoter, but simply coping a .h and a .m file from one project directory to another is much easier.

While that part might have become easier the building process did not. And since programers are lazy people otherwise they wouldn't have been programmers, then they would have used paper and pencils, they created a solution called make. make is a tool that hence the name automates the build proces.

Create a Makefile, note the capital M, like this:
all: main.o Greeter.o
	gcc -lobjc -o Greet main.o Greeter.o
main.o:main.m Greeter.h
	gcc -c main.m
Greeter.o:Greeter.m Greeter.h
	gcc -c Greeter.m
Note the idents must be a TAB and not 8 spaces.

Makefiles

Makefiles have a very simple syntax:
target: needs
	commands
From our example the first target you see is all. all is a make keyword, every Makefile needs a all target. Because running make without an argument assumes make all.

Before the command associated with all is run it needs main.o and Greeter.o. Luckily the Makefile also has those targets (you can name the targets anything you want, but this is the easiest to remember).

For every target it is checked if it needs are forfilled before the command is run. This is essentially what make does. This guide is not about Makefiles, so if you would like to more on this subject, read GNU Make

Save the file and type:
make
Recognize all the commands we just typed ourselfs? If we now make changes to one of the files, retype make all is done automatically. Isn't that great!


Chapter 3. Inside objects

Ils ont change ma chanson, ma

As mentioned before Objective-C is an extension to the C programming language, which makes C object oriented. Then I told you that it wasn't something you wanted to know. I lied, you do want to know that. Without C there wouldn't be Objective-C. Objects in itself contain C code, so this section will introduce to you the basic parts of C, which happens to be the basic parts of Objective-C.

We will start with data and then look at functions, because that are the two elements that make up every computer language and an object.


Data

c'est la seule chose que je peux faire

There are two different kinds of programming languages. The first one is called statically typed and the other is called a dynamically typed language. The difference between the two has to do with how values are assigned to variables. A variable is a named container for a value. Like, VAR=1 means that the variable called VAR has the value 1. This assignment is dynamically, because we haven't told anybody that VAR actually contains an integer. This means that apperently VAR can hold any value. In a dynamically typed language VAR=a would also be legal.

However C is a statically typed language. Which means we have to tell upfront what kind of data a variable is going to hold. To do this the language provides us with predefined data types, with which we can initialize a variable. To e.g. tell a compiler that we use two integers in a program, one with the value 1 and the other with value 5, we do the following: Create a project directory called Numbers and put the following four files in it.

Integers.h:
/* Integers.h written by Dennis Leeuw */

#include <objc/Object.h>

@interface Integers:Object
{
	/* No instance variables */
}

- (void)integers;

@end
Integers.m:
/* Integers.m written by Dennis Leeuw */

#include <stdio.h>
#include "Integers.h"

@implementation Integers

- (void)integers
{
	int i;
	int j;

	i = i;
	j = 5;

	printf("I=%d, J=%d\n", i, j);
}

@end
main.m:
/* main.m written by Dennis Leeuw */

#include "Integers.h"
#include <stdlib.h>

int main(void)
{
	id integer;
	integer=[Integers new];

	[integer integers];

	[integer free];
	return EXIT_SUCCESS;
}
Makefile:
# Makefile written by Dennis Leeuw

all: main.o Integers.o
	gcc -lobjc -o Numbers main.o Integers.o
main.o: main.m Integers.h
	gcc -c main.m
Integers.o: Integers.m Integers.h
	gcc -c Integers.m

Run make. When you remove the line: int i, j; and then recompile the code, you get the warning: `i' undeclared (first use in this function) which exactly proves that C is a statically typed language. You need to declare your variables before you can work with them.

And since you need to type your variables, there are predefined types.

Data types

Data types tell the computer the kind of data that is represented, which actually means the amount of memory that needs to be reserved to store information. To give you an overview of data types and the memory that is needed:

Table 3-1. C standard types

TypeDescriptionSize
charA character of the local character set1 byte (8 bits)
intAn integer (whole numbers), e.g. 1, 2, 9, 10004 bytes (32 bits)
floatFloating point number, e.g. 1.2, 1.7, 5.84 bytes (32 bits)

char. Is the basic unit within a Objective-C and C program. All others are derived from the size of char. char actually is a single character like 'a' or '3'. It's size is defined in limits.h, which should reside in /usr/include. In my limits.h file it says:
#  define CHAR_BIT      8
which means a char is 8 bits.

Table 3-2. Derivative types

TypeDescriptionSize
shortA short integer2 bytes
longA double short4 bytes
long longA double long8 bytes
doubleDouble precision float8 bytes

long. Note that a long is equal to an int (? true ?)

Table 3-3. Objective-C data types

TypeDescriptionSize
BOOLBoolean type which can either be YES or NO. NO is 0, YES is non-0. 
idAn object4 bytes
STR  
IOD  
SEL  
IMP  

id. id is the data type that indicates that we are talking about an object. So to declare a variable greeter we proceed it by id. With which we tell that greeter is an object with its own rules.

All mentioned lengths are the most common ones for 32 bit machines, like the Intel Pentium and compatible chipsets. The actual length is machine dependend and can be found in the limits.h file and the float.h. Or can be shown with a little program like this:

Sizes.h:
/* Comments
** Example written by Dennis Leeuw
*/

#include <objc/Object.h>

@interface Sizes:Object
{
         /* This is left empty on purpose:
	 ** Normally instance variables would be declared here,
	** but these are not used in our example.
	*/
}

- (void)sizes;

@end
Sizes.m:
/* Comments:
** Example written by Dennis Leeuw
** C code by Pascal Bourguignon
*/

#include <stdio.h>
#include "Sizes.h"

@implementation Sizes

- (void)sizes
{
        printf("sizeof(char                )=%4d\n",sizeof(char));
	printf("sizeof(unsigned char       )=%4d\n",sizeof(unsigned char));
	printf("sizeof(short               )=%4d\n",sizeof(short));
	printf("sizeof(unsigned short      )=%4d\n",sizeof(unsigned short));
	printf("sizeof(int                 )=%4d\n",sizeof(int));
	printf("sizeof(unsigned int        )=%4d\n",sizeof(unsigned int));
	printf("sizeof(long                )=%4d\n",sizeof(long));
	printf("sizeof(unsigned long       )=%4d\n",sizeof(unsigned long));
	printf("sizeof(long long           )=%4d\n",sizeof(long long));
	printf("sizeof(unsigned long long  )=%4d\n",sizeof(unsigned long long));
	printf("sizeof(float               )=%4d\n",sizeof(float));
	printf("sizeof(double              )=%4d\n",sizeof(double));
	printf("sizeof(void                )=%4d\n",sizeof(void));
	printf("sizeof(id                  )=%4d\n",sizeof(id));
}

@end
 
main.m:
/* Comments:
** Example written by Dennis Leeuw
*/

#include "Sizes.h"
#include <stdlib.h>

int main(void)
{
        id sizelist;
	sizelist=[Sizes new];
		        
	[sizelist sizes];

	[sizelist free];
	return EXIT_SUCCESS;
}
 
Makefile:
all: main.o Sizes.o
        gcc -lobjc -o Sizelist main.o Sizes.o
main.o: main.m Sizes.h
	gcc -c main.m
Sizes.o: Sizes.m Sizes.h
	gcc -c Sizes.m
 

The output this program returns is the relative size to the size of char. So if char is 8 bits and short int is 16, it will mention short =2. Since the ANSI C standard specifies sizeof(char) is equal to 1 by definition and sizeof(char)<=sizeof(short)<=sizeof(int)<=sizeof(long). But I think we are already to far away from the path we want to follow...

You might know that computers only use a 1 and a 0 for their computations. That's why they call it a binary, from bi: 2. So everything we write in a program is actually converted to 1s and 0s. If we say that a integer is defined in a program, we actually mean that a piece of memory is reserved to store the amount of data that is asociated with an integer.

So let's have a look again at our Numbers program. We defined i and j to be short integers and from the above table we can read that that means that we use 32 bits of memory space for these values. So if we write our decimal numbers 1 and 5 into binary format that would mean:

Table 3-4. Decimal to binary

DecimalBinary
100000000000000000000000000000001
500000000000000000000000000000101

With those 32 bits we can represent numbers ranging from 0 to 429496729. This is what is called a unsigned int.

Now change the int to short int, and you will see that it still works. What we just did, is called optimization. Since we know that i, and j, will always be 1 and 5, there is no need for them to occupie 32 bits of memory. Those values can be stored in 16 bits, so that is what we did. We told the compiler that i and j are both short integers, and saved 2 times 16 equals 32 bits of memory space.

Up until now we have worked with characters and integers, that both always represent whole numbers. If we however assign 0.1 to i. The compiler doesn't complain, but when we look at the output as soon as we run the number command. You will see that i now has a value of 0.

This is not what we want. Change the Integer.m file to look like this, and mark the changed prinf statement!:
/* Example written by Dennis Leeuw */

#include <stdio.h>
#include "Integers.h"

@implementation Integers

- (void)integers
{
        float i;
	short int j;

	i = 0.1;
	j = 5;

	printf("I=%f, J=%d\n", i, j);
}

@end

The output of number should look like I=0.100000, J=5. i is a floating point number, but what does this mean for our memory consumption? From the table we know that we now use 32 bits of memory space.

We might also want to represent negative numbers, e.g. -1. Edit the program, change the i = 0.1; to i = -1;, make i a short int and recompile. No errors where produced, so somehow the computer new it was a negative number and could work with it. How is that done?

The agreement is that negative numbers are representations of the normal number, with all bits negated and then 1 added. Which means that -1 is written as:

Table 3-5. Creating -1

1:0000000000000001
negation:1111111111111110
add 1:0000000000000001
-1:1111111111111111

If we do the same for -5. That would look like this:

Table 3-6. Creating -5

5:0000000000000101
negation:1111111111111010
add 1:0000000000000001
-5:1111111111111011

What actually happens is that the first bit, when read from left to right, is the sign bit and tells our computer that we are working with negative numbers. The effect is that we now can address numbers in the range from -32768 to 32767 (since we are using short ints that normaly range between 0 and 65535), and the typing in the program should have been signed short int. Due to the intelligence in the gcc compiler, the problem was solved and no warnings where produced.

In our first numbers program we unknowingly used a prefix before our data type declaration of 'unsigned' (meaning whole positive numbers). As we have discovered now there are two types of prefixes: unsigned and signed.

For testing sake, change Integers.m to the following and compile:
/* Example written by Dennis Leeuw */

#include <stdio.h>
#include "Integers.h"

@implementation Integers

- (void)integers
{
        unsigned short int i;
	unsigned int j;

	i = -1;
	j = 5;

	printf("I=%d, J=%d\n", i, j)
}

@end

Notice that we declared i as an unsigned int, which means we can not use negative numbers, but assign -1 to i. The compiler will not complain about this, but when we do run the program, the output might suprise us: I=65535, J=5. Ofcourse this is not correct, but I wanted to show you how one can easily shoot oneself in the foot.

Now that we have seen the different data types, it might be useful to do something with them. After all the thing you are working on is called a computer so lets compute!

Operators

Table 3-7. Arithmetic operators

OperatorFunction
+Addition
-Substraction
/Division
*Multiplication
%Modulus

Table 3-8. Relational operators

OperatorFunction
>Greater then
>=Greater then or equal to
==Equal to
!=Not equal to
<=Less then or equal to
<Less then

Table 3-9. Logical operators

OperatorFunction
&&AND
||OR
!NOT

The relational and logical operators together form the Boolean operators since their result is always TRUE or FALSE.

Change Integers.m to look this:
/* Integers.m written by Dennis Leeuw */

#include <stdio.h>
#include "Integers.h"

@implementation Integers

- (void)integers
{
	unsigned short int i;
	unsigned short int j;
	unsigned short int s;

	i = i;
	j = 5;
	s = i + j;

	printf("%d + %d = %d\n", i, j, s);
}

@end
Rerun make and execute Numbers. The output might come as no surprise. Now change s = i + j; to s = i - j; and change the printf statement accordingly, and the outcome might also be no surpise. Change the unsigned short int of s to signed short int. And every thing is alright. One could even remove the signed part and all stays well.

Let's try division, by replacing the - sign by the / sign. Now the outcome is 1 / 5 = 0. Which is correct when talking about integers but not in real life, so let's make s a float, and replace the last %d in the prinf statement by %f. Still the outcome is 0.000000, because the i and j are integers, so what we need to do is something that is called typecasting.

Replace s = i / j; by s = (float) i / j;. This means that our integer i is first converted to a float, then the division is performed, and the outcome assigned to s.

Typecasting

Typecasting allows you to do on the fly type conversions. Typecasting is done by using the needed type in parentheses, (), and putting it in front of the value or variable you want to change.

I feel I am getting the hang of it. It almost seems easy. Let's do something more complex.

Up until now we have worked with single entities asignments. To take a char example: char a; a='A';. But what if you want to assign a whole word, or even a sentence?

More then single byte chars do not exist, but arrays do.

Array

An array is a named container that can hold several identical data types. Like an array of integers, an array of characters (also called a string), an array of floats, etc.

An array is defined by first giving the type, then the name and between [] the amount of elements that the array can hold.
int a[10];  /* Array of integers that can hold 10 integer values     */
char b[20]; /* Array of chars that can hold 20 characters            */
float c[5]; /* Array of floats that can hold 5 floating point values */
Numbers start from 0, so the first element in a is a[0], followed by a[1], a[2], a[3] and ending by a[9].

A little experimenting with arrays, resulted in the following example:
/* Integers.m
** Example written by Dennis Leeuw
*/

#include <stdio.h>
#include "Integers.h"

@implementation Integers

- (void)integers
{
        char w[4];

	w[0]='H';
	w[1]='e';
	w[2]='l';
	w[3]='o';

	printf("%c%c%c%c%c\n", w[0],w[1],w[2],w[2],w[3]);
}

@end

First of all put your characters between ''. If you don't the compiler will treat them as variables, and says they are undeclared.

The thing is that this will print a nice Hello to your screen, and it illustrates the use of arrays on characters, although I must admit that a simple printf("Hello"); would have been easier.

FIXME: Complex arrays... box...

The idea is clear I hope, an array is a list of elements of the same type. The next data element might not come as an surprise. We are going to create a data element that is a list of different data types within one structure, hence the name structure.

TODO: Structure, Pointer


Functions

et ce n'est pas bon, ma

Next to data and data-types, the basic routines to manipulate data are functions. Every object within an object oriented language consists of data and functions, and to get a better understanding of that I will now introduce you to functions.

Within C programming a function definition looks like this:
return-type function-name(parameter declaration, if any)
{
	declarations;
	asignments;
	statements;
}

As mentioned before the function-name can be anything as long as it is not main. You will hopefully also note that a function has a return-type and might have parameters.

Every function should return something when it is finished. It might be that it tells that it finished okay, like our return 0; statement, or it can return anything else. You might have noticed that all our examples main functions had a return-type of int, which corresponds to the return 0;.

Other values are ofcourse possible, and they must be the same as one of the data-types we discussed. Since we can only return things that do exist, don't we. So the table of the different return-types is identical to the list of data-types.

For the parameter declaration more or less the same is true. The parameter declaration describes the data the function expects. In our case all main are defined as void, which means they don't expect any input (for non-english speakers: void means something like empty).

FIXME: In the main function we tell thus that the return-type of the function is an int and that there are no parameter declarations (this means the function does not accept any arguments, you can not send data to this function), since it says void . Then there is the compound statement {} which tells that everything that follows belongs to the function named main.

As we have seen in our Hello, World! example a function might come from an external library. We will soon learn that most functions will come from external sources since C and thus Objective-C is in it self a very small and compact language. Only the bare minimum is available. I will use this section to get you familiar with that bare minimum.

Change Integers.m to the following:
/* Comments:
** Example written by Dennis Leeuw
*/

#include <stdio.h>
#include "Integers.h"

@implementation Integers

- (void)integers
{
        short int i;
	short int j;
	float s;

	i = 1;
	j = 5;
	s = (float) i / j;

	if (s < 0)
		printf("s=%f is less then 0\n", s);
	else if (s == 0)
		printf("s=%f is equal to 0\n", s);
	else
		printf("s=%f is greater then 0\n", s);
}

@end
run make and do ./Numbers. The outcome might surprise us: s=0.200000 is greater then 0. On the otherhand the computer is right. One fifth is more then nothing.

Change the s = (float) i / j; to s = i - j and you will see that s is less then 0. Now you can fool around with this if you like. I know I did.

if ... else

For testing on boolean trueness there is the if ... else construction. The general form is:
if (test)
	do_something
else
	do_something_else
Where the else construction might be omitted.

The logic behind this is that if the test between parenthesis is true the do_something is executed, while if it is not true the do_something is skipped. Complex tests can be created by using else if constructions.

The do_something or do_something_else can only be single statements. While test can be a complex boolean expression with by parenthesis grouped tests, like:
if ((x<y) && (a==b) || (k<=m))
	printf("That's complex");

If we can test on things being true or false, we can create loops. Let's investigate. I found out there are three different ways of creating loops. There is while, there is do and there is for. I'll give you examples of while and for, since the do-loop is just a while-loop. We start with while:
/* Integers.m
** Example written by Dennis Leeuw
*/

#include <stdio.h>
#include "Integers.h"

@implementation Integers

- (void)integers
{
        short int i;
	short int j;
	short int s;
	
        i = 1;
	j = 5;
	s = i - j;

	while ( s < j )
	{
		printf("s=%d and j=%d\n", s, j);
		s = s + 1;
	}
}
@end
I think this example speaks for itself.

while

The abstract definition of a while loop looks like this:
while (test)
{
	statement;
}
which can be read as while test is true do statement. So as long as the boolean test is true statement is executed. If you replace test by 1, which makes the while test always true, you have an endless loop.

Note the block symbols {} that group the statements. If you only have a single statement you can ofcourse leave out the block symbols.

The nice thing about prgrammers, to me, is that they are lazy people. If things can be made easier (less typing) they will do so. The line s = s + 1; is an example of too much typing. The short hand notation would be s++;

Table 3-10. More short hand notations

NormalShort
s = s + 1;s++;
s = s - 1;s--;
s = s + 5;s += 5;
s = s * j;s *= j;

Rewriting the above while-loop into a for-loop looks like this:
/* Integers.m
** Example written by Dennis Leeuw
*/

#include <stdio.h>
#include "Integers.h"

@implementation Integers

- (void)integers
{
        short int i;
	short int j;
	short int s;

	for ( i=1,j=5,s=i-j; s<j; printf("s=%d and j=%d\n", s, j),s++ );
}

@end
I admit this is not very readable, but it is an example.

Let me start by creating a more readable format for the for loop:
for ( i=1,
      j=5,
      s=i-j;

      s<j;

      printf("s=%d and j=%d\n", s, j),
      s++
      );
recognize our while-loop again? By the way, you can do this in your code too. The compiler doesn't care how you format your program, as long as you stick to the syntax.

TODO: break/continue, switch, goto


C more ...

This chapter was actually a very short C course, wrapped in Objective-C. Almost all examples could have been plain C programs. It illustrates the closeness of Objective-C and C. With what I have written (and learned myself) we hopefully have enough basis to learn more about Objective-C. As said in the introduction this guide will not master you in Objective-C, just gets you started.

But it should feel nice that a simple C course can fit into a single chapter. The downside of all this is that because C and thus Objective-C is such a simple language you need to do a lot yourself, or use someone elses code.

There are a lot of good C courses, and very fine books on C programming. If you like to know more about C I would like to point you to atleast the Learning GNU C book. We will continue our journey to get familiar with Objective-C and especially GNU Objective-C since that is what is provided by the GNU Compiler Collection.


Chapter 4. Getting help

But maybe it'll all be alright ma

The above chapters have given you an almost complete description of the Objective-C language. If you need more (and trust me you do), you need to use code from others. That might be provided through the C-library or Objective-C runtime on your system, or it might be libraries, functions or objects from others.

Most standard C functions are explained well in other documents, but there is also a lot of documentation already available on your system through the manual-pages and the header-files.


Reading man-pages

well if people are buying tears

man 3


Reading .h files

I'll be rich some day ma

Object.h


Chapter 5. Keep It Simple, Stupid

Look what they done to my song, ma

Object.h

Well they tied it up in a plastic bag

Object.h, Protocol.h And friends


Protocol.h

and turned it upside down ma

Object.h, Protocol.h And friends