11.3. More Features

11.3.1. Visibility

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.

11.3.2. The Object Class

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.

11.3.3. Arrays

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);
}