I start with the traditional "Hello World" program, which is mainly a demonstration of gnustep-make. There is an "Beginners Guide to Objective-C Programming" about Objective-C language itself.
main.m:
#include <stdio.h> int main(void) { printf("Hello World\n"); }
This is a very simple program, not even an Objective-C program. In order to compile it, I need a GNUmakefile file, which is a simplified, but powerful version of Makefile.
GNUmakefile:
include $(GNUSTEP_MAKEFILES)/common.make APP_NAME = HelloWorld HelloWorld_HEADERS = HelloWorld_OBJC_FILES = main.m HelloWorld_RESOURCE_FILES = include $(GNUSTEP_MAKEFILES)/application.make
Type 'make', and you will find a directory called "HelloWorld.app". That's the GNUstep application. This directory contains all it needs. Therefore, it is safe to move the whole application without breaking it. Use 'openapp HelloWorld' to open this application. It will print "Hello World" as you expect.
There are some GNUmakefile tutorials. Therefore, I won't touch this topic too much. Here is another example, which is a real Objective-C program. If you are not familiar with Objective-C, read the Objective-C book from apple first.
There are four files:
say.h:
#ifndef _Say_H_ #define _Say_H_ #include <Foundation/NSObject.h> @interface Say: NSObject { } - (void) sayHello; - (void) sayHelloTo: (NSString *)name; @end #endif /* _Say_H_ */
say.m:
#include "say.h" #include <Foundation/Foundation.h> @implementation Say - (void) sayHello { NSLog(@"Hello World"); } - (void) sayHelloTo: (NSString *)name { NSLog(@"Hello World, %@", name); } @end
main.m:
#include "say.h" #include <Foundation/Foundation.h> int main (void) { id speaker; NSString *name = @"GNUstep !"; NSAutoreleasePool *pool; pool = [NSAutoreleasePool new]; speaker = [[Say alloc] init]; [speaker sayHello]; [speaker sayHelloTo:name]; RELEASE(speaker); RELEASE(pool); }
GNUmakefile:
include $(GNUSTEP_MAKEFILES)/common.make APP_NAME = HelloWorld HelloWorld_HEADERS = say.h HelloWorld_OBJC_FILES = main.m say.m HelloWorld_RESOURCE_FILES = include $(GNUSTEP_MAKEFILES)/application.make
Again, use 'make' and 'openapp' to compile and run this application. This example is self-explained. There are several things worthy to metion.
In Cocoa, #import is used instead of #include to prevent duplicated declarations. But GNU GCC doesn't support #import as good as Apple's GCC, and GNUstep use #include. Therefore, it is better to use #include for GNUstep appplication, which can still run on Cocoa environment. The way #include to prevent duplicated declaration is #ifndef ... #define ...#endif. Just put in a unique name. And in headers, try to use as few #include as possible to speed up the compilation. You can always put the #include in source code files (.m).
The class "Say" inherits from "NSObject", which is the root class of GNUstep. Always inherit from NSObject if you don't know which class to use. NSObject contains many fundamental methods which you won't want to implement by yourself.
NSLog() is used instead of printf() because it is as easy as printf(). And most importantly, NSLog() accept the %@ symbol, which represents an object. That means you can print objects in NSLog(). Very handy for debug.
NSString is one of the most used classes in GNUstep. You can use @"..." to create a NSString. There are many useful methods in NSString to manipulate strings and paths. Check these articles: String in Cocoa: Part I, Part II
NSAutoreleasePool is the place for autoreleased instances. In this example, it is not much useful, but I think it is a good habit to use it. When the application should end, remember to release it. Methods -alloc and -init is the standard method to create an instance. Method -new is a shortcut if there is no messages for -init.
Here is a demonstration of file I/O. GNUstep offer NSFileHandle and NSFileManager to handle files. NSFileHandle is mainly to read and write, and NSFileManager is for file management.
main.m:
#include <Foundation/Foundation.h> int main (void) { NSString *path; NSAutoreleasePool *pool; NSFileHandle *readFile, *writeFile; NSData *fileData; pool = [NSAutoreleasePool new]; path = @"main.m"; readFile = [NSFileHandle fileHandleForReadingAtPath:path]; fileData = [readFile readDataToEndOfFile]; writeFile = [NSFileHandle fileHandleWithStandardOutput]; [writeFile writeData:fileData]; RELEASE(pool); return 0; }
GNUmakefile:
include $(GNUSTEP_MAKEFILES)/common.make APP_NAME = FileHandle FileHandle_HEADERS = FileHandle_OBJC_FILES = main.m FileHandle_RESOURCE_FILES = include $(GNUSTEP_MAKEFILES)/application.make
It is not too much useful to only trasfer data in NSData. Here, I can take the data out of NSData and manipulate it in C. By this way, I can combine GNUstep with C libraries.
main.m:
#import <Foundation/Foundation.h> int main (void) { NSString *path; NSAutoreleasePool *pool; NSFileHandle *readFile; NSData* fileData; char *buffer; unsigned int length; pool = [NSAutoreleasePool new]; // path = @"main.m"; path = @"GNUmakefile"; readFile = [NSFileHandle fileHandleForReadingAtPath:path]; fileData = [readFile readDataToEndOfFile]; length = [fileData length]; buffer = malloc(sizeof(char)*length); [fileData getBytes: buffer]; printf("%s\n", buffer); printf("%d\n", length); free(buffer); RELEASE(pool); return 0; }