By default, Objective C adopts Smalltalk's visibility rule: attributes are private and method are public. However, it also allows to override this rule using the directives @private, @protected, and @public. All attributes or method following one of these directives aquire the associated visibility. Private access is retricted to the class itself (and its categories), protected access to the class and its subclasses and public access to everybody.
@interface Account : Object { @private int number; @public double balance; } - init: (int)aNumber; @end @implementation Account - init: (int)aNumber { number = aNumber; balance = 0; } @end main() { Account* account = [[Account alloc] init: 123]; printf("balance=%f", account->balance); }
A public instance variable can be accessed from outside the class just like an element of a C structure, but the object needs to be statically typed. In practice, public instance variables are hardly used, and in most cases the default visibility rule works just fine.
Every Objective C environment is shipped with a base class which provides common behavior for all objects. The GNU compiler offers the the Object, and the OpenStep/Mac OS X system has the NSObject class. Both provide a large number of methods covering memory management (alloc, free, copy), comparison (isEqual, compare, hash), and access to the underlying class and messaging. NSObject adds amoung other things a reference counting interface which provides a simple memory management scheme.
As an example of the meta information which is available at run-time, you can ask an object for its class or check if it belongs to a class or one of its subclasses.
main() { id employee = [[Employee alloc] init]; printf("class=%s\n", [[employee class] name]); printf("is kind of Person=%d\n", [employee isKindOfClassNamed: "Person"]); printf("is member of Person=%d\n", [employee isMemberOfClassNamed: "Person"]); } class=Employee is kind of Person=1 is member of Person=0
Since Employee is derived from Person, the "is kind of" relationship is satisfied, but the employee is not a member of the Person class.
Since the class information is available at run-time, it is also possible to vary the message itself at run-time, that is, to determine the message selector dynamically.
main() { id person = [[Person alloc] init]; SEL selector = @selector(display); [person perform: selector]; [person free]; }
The @selector directive gives us the selector object for a selector name, and the perform: method calls the messaging mechanism directly with this selector.
Object oriented systems thrive on their libraries, and Objective C is no exception. The combination of static types on the one hand and dynamic features on the other (including extending existing classes) provide a good foundation for powerful libraries. The NeXTStep/OpenStep/OS-X system as the example for an Objective C framework provides classes covering everything from basic collections and operating system function to graphical user interfaces. We can only give a first glimpse here using the GNU's GNUStep implementation.
Since GNUStep is not part of the standard gcc installation, we have to make sure that the libraries are known to the compiler and linker. The easiest way to accomplish this is to use GNUStep's make system. Here is the GNUmakefile for the example below.
GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles include $(GNUSTEP_MAKEFILES)/common.make # The tools to be compiled TEST_TOOL_NAME = sample # The Objective-C source files to be compiled sample_OBJC_FILES = sample.m SRCS = $(TEST_TOOL_NAME:=.m) HDRS = DIST_FILES = $(SRCS) $(HDRS) Makefile include $(GNUSTEP_MAKEFILES)/test-tool.make
Besides demonstrating GNUStep's array objects, the following example also introduces a number of important GNUStep features such as memory management with "auto release pools" and string constants.
#include <Foundation/Foundation.h> #include <Foundation/NSString.h> #include <Foundation/NSArray.h> static int compare(id a, id b, void* context) { return [a compare: b]; } int main() { CREATE_AUTORELEASE_POOL(pool); NSString* name = @"Homer"; NSArray* a = [NSArray arrayWithObjects: @"one", @"two", nil]; NSLog(@"a=%@\n", a); NSObject* obj; NSEnumerator* enumerator = [a objectEnumerator]; while ((obj=[enumerator nextObject])) { NSLog (@"Next Object is: %@", obj); } NSMutableArray* ma = [NSMutableArray array]; [ma addObjectsFromArray: a]; [ma addObject: @"three"]; NSLog(@"ma=%@\n", ma); [ma sortUsingFunction: compare context: nil]; NSLog(@"ma=%@\n", ma); DESTROY(pool); }