Working with Objects
********************

Selectors
=========

A principal OO addition to Objective-C is the syntax to send messages to objects:

     [myArray removeObjectIdenticalTo: anObject];

The example sends the message named removeObjectIdenticalTo: to myArray with the argument anObject.

Instead of using this syntax to send a message, the selector of a message may be used.  The selector is a way of referring to an abstract message, it is a representation of the message name without the argument or the receiver.

Objective-C introduces a new data type: SEL for variables that hold selectors.  A SEL variable is implemented as a pointer to a structure containing the name (and often incidental information about the return type and argument types) of the selector.

You can obtain a selector in a variety of ways -

  * At compile time, you can use the @selector() directive -

            SEL	mySelector = @selector(removeObjectIdenticalTo:);

  * At runtime, you can use the NSSelectorFromString() function -

            SEL	mySelector = NSSelectorFromString(r̈emoveObjectIdenticalTo:");

  * In a method, you can refer to the variable _cmd which contains the selector for the current method -

          - (void) removeObjectIdenticalTo: (id)anObject
          {
            SEL	mySelector = _cmd;

            // Method implementation here ...
          }

Sending messages to objects, and invoking methods that are named by the message selector can be achieved using performSelector: and related methods:

     [receiver performSelector: mySelector];
     [receiver performSelector: mySelector withObject: arg1];
     [receiver performSelector: mySelector withObject: arg1
       withObject: arg2];

  * receiver - the object receiving the message.

  * mySelector - the selector of the method to be performed.

  * arg1 arg2 - arguments sent with message.

  * messaging instructions are converted into runtime calls, explanation

  * what are selectors, efficiency reasons.

  * using selectors in practice <Use NSStringFromSelector etc, only quote the existence of low level runtime calls>

  * methods and selectors

  * method return and argument types

  * varying the message at run-time

The GNU Objective-C runtime library provides a function sel_eq() which may be used to test for selector equality.  This is necessary because, while the compiler tries to ensure that compile-time generated references to selectors for a particular message point to the same structure, selectors produced at runtime, or in different compilation units, will be different and a simple pointer equality test will not do.

Target-Action concept
---------------------

The Target-Action paradigm is used a great deal in the GNUstep GUI, but infrequently in other code,  it is most applicable when building a network of related objects that can interact relatively simply.

The idea is that an object may have a target ... an instance variable of type id which refers to a target object, and an action ... an instance variable of type SEL.

When the object is told to perform its action, it asks the target to perform the action, passing itsself as the argument.

Neither object needs to know anything about the other object at compile time, so such objects can be connected together in a running program to build new behaviors into applications.

The code to implement this paradigm is simple -

     - (id) performAction
     {
       if (action == 0)
         {
           return nil;	// No action set ... do nothing
         }
       if (target == nil)
         {
           return nil;	// No target set ... do nothing
         }
       if ([target respondsToSelector: action] == NO)
         {
           return nil;	// Target cannot deal with action ... do nothing
         }
       return [target performSelector: action withObject: self];
     }

As an example, consider a character attempting to make use of an object they have found while they are standing in front of a door -

       [obj setAction: @selector(openWith:)];
       [obj setTarget: theDoor];
       if ([obj performAction] == nil)
         {
           // Door didn't open.
         }
       else
        {
         // Door opened.
        }

The door object will be sent the openWith: message with the new object as its argument.  If obj happens to be a key, the door may decide to open.  It may also open in response to an object that happens to be a battering ram.  The same fragment of code would handle both cases.

Avoiding Messaging Errors with respondsToSelector:
--------------------------------------------------

Using typed objects as shown below, the compiler would forewarn you if the anObject was unable to respond to the alert: message, as it knows what type of object anObject is:

     AnObject	*anObject;		// an instance of AnObject class

     anObject = [[AnObject alloc] init];	// build and initialize the object
     [anObject alert: additionalObject];	// send it a message.

However at times the compiler will not forewarn you that a message will attempt to invoke a method that is not in the receiver's repertoire. For instance, consider the code below where anObject is not known to implement the alert: message:

       id		anObject;		// arbitrary object;

       anObject = [[AnObject alloc] init];	// build and initialize object
       [anObject alert: additionalObject];	// send it a message.

In this case, the compiler will not issue a warning, because it only knows that anObject is of type id ... so it doesn't know what methods the object implements.

At runtime, the Objective-C runtime library will fail to find a method implementation for the alert: message in the AnObject class, so it will send a forwardInvocation: message to anObject instead. The default implementation of the forwardInvocation: in the NSObject class will then raise a runtime exception which, if uncaught, will cause the program to crash.

In order to avoid this sort of problem, your code can use the respondsToSelector: method to see if an object can handle a particular message -

       id		anObject;

       anObject = [[AnObject alloc] init];
       if ([anObject respondsToSelector: @selector(alert:)] == YES)
         {
           [anObject alert: additionalObject];	// send it a message.
         }
       else
         {
           // Do something else if the object can't be alerted
         }

Note. Protocols may be used to handle unrecogized message checking at compile time.

Initializing and Allocating Objects
===================================

The NSObject class defines two allocation methods namely alloc and allocWithZone:.

     + (id) alloc;
     + (id) allocWithZone: (NSZone*)zone;

Both methods will allocate memory to hold an object, and initialise the objects' isa pointer, which as previously discussed defines the class to which the object belongs. The same initialization procedure sets all remaining instance variables to 0.

In practice further initialization procedures are implemented by instance methods beginning with the familiar init... syntax, and an object is not considered initialised until one of these methods has been executed (the exception being in the case of copied objects).

Note. Classes must provide init methods to initialize their declared instance variables.

init and Returned Objects
-------------------------

After initializing the instance variables of the receiver, an init... method returns a usable object, which might not be the receiver, however.

Here is an scenario where the returned object is not the receiver: the class NSConnection only permits one connection to exist between any two ports, so if you call initWithReceivePort:sendPort: when a connection for the ports exists, the method will deallocate the newly allocated instance, and return the current conflicting object, rather than the receiver.

The init... method may also return nil at times when it is passed an argument that does not compute; for example the argument to the NSString method initWithContentsOfFile: may be an erroneous file name.

  * allocating vs initializing objects

Allocating Memory
-----------------

Typically memory is allocated in zones, and most memory is allocated from the default area (which is returned by the NSDefaultMallocZone()) function. When it is necessary to group objects in the same area of memory - perhaps for performance reasons, you may create a zone from where you would allocate those objects. This will minimise the paging required by your application when accessing those objects frequently.

Low level memory allocation is performed by:

  * NSAllocateObject()

  * NSDeallocateObject()

These are rarely used but are available when you require more advanced control or performance. These functions are called by [NSObject +allocWithZone:] and [NSObject -dealloc]. If you call NSAllocateObject() directly to create an instance of a class, you may break some functionality of that class, such as caching of frequently used objects.

Objects are destroyed using dealloc, and are created using:

  * +alloc

  * -copy

  * -mutableCopy

The allocation methods are covers for the following more versatile methods:

  * +allocWithZone:

  * -copyWithZone:

  * -mutableCopyWithZone:

These methods may specify zones from which the memory is allocated, rather than use the default zone. NSObject also provides +new, which is simply a cover for the combination of +alloc and -init.

The -dealloc method returns the memory occupied by the object to the zone from which it was originally allocated; it can use the -zone method to determine which zone this is.

Explicit memory allocation and deallocation is efficient - but when you pass objects around inside a program (and especially from/to libraries etc.,) it quickly becomes difficult and/or inefficient to keep track of who owns an object, and who should be responsible for calling its deallocation method.

The OpenStep specification remedies this problem by providing a reference counting mechanism along with a set of conventions that make memory management easy.

Additionally, the GNU Objective-C compiler and the GNUstep system provide a memory sweeping garbage collection mechanism using the Boehm conservative garbage collection library.

Memory Deallocation
-------------------

The dealloc method is defined in the NSObject class and releases memory allocated to the receiver. The NSObject implementation of the method deallocates only instance variables. Additional allocated, unshared memory used by the object is deallocated separately. Other entities that depend solely on the deallocated receiver, including complete objects, must also be deallocated separately.

In this instance subclasses of NSObject override the dealloc method. Every class that has its objects allocate additional memory must have its own dealloc method. Each version of dealloc ends with a message to super to perform an inherited version of the method, as illustrated in the following example:

     - (void) dealloc
     {
       RELEASE(anObject);
       NSZoneFree(myZone, myMemory);
       [super dealloc];
     }

(See Section Memory Deallocation.)

The +alloc method is not guaranteed to return an object created using NSAllocateObject().  It may actually return any object, though convention dictates that the return value is an object with its isa instance variable set to point to a class which is a subclass of that to which the alloc message was sent, and which can respond to the initialisation methods of that class.

For instance, the method may return a placeholder object that will be replaced by another object depending on the initialisation method that is sent to it.

NB. exception ... it is permitted to return nil on allocation failure.

When an object is initialised, the return value of the initialiser is the new value of the object (or nil) ... the initialiser is permitted to replace one object with another. This behavior enables a class to share objects (and do other tricky things) -

     @implementation Crown
     - (id) initWithLevel: (CharacterLevel)level
     {
       if (level > wizardLevel && [crownOfTheEmperor isOwned] == NO)
         {
           RELEASE(self);
           [crownOfTheEmperor setOwned: YES];
           self = RETAIN(crownOfTheEmperor);
         }
       else
         {
           self = [super init];
           if (self != nil)
             {
               // Perform standard initialisation here.
             }
         }
       return self;
     }
     @end

In the above example, the initWithLevel: method is used to create a crown discovered in a random treasure store.  If certain conditions are met, the system returns a special object ... only one of which may exist and be owned by a character.

In this case, the initialiser for a crown expects a character level as an argument, and the old crown object is released and replaced by a special one.

In the preceding example, the standard route through the initialiser was to call the initialiser of the superclass, and assign the result to self before initialising instance variables and returning self.

This is necessary because, unlike in C++ or Java, the Objective-C language does not enforce initialisation ... so it's up to you as the programmer to ensure that superclasses are permitted to perform their object initialisation code before the subclass performs its initialisation (actually, this gives you the flexibility to change how things are initialised ... but you should obey the conventions unless you are sure you know what you are doing).

An initialiser of any class intended for re-use/subclassing should therefore not replace self with an object of a class that is not a subclass of the original (though it is legal to return nil, and you should therefore check for that in your code).

This rule is essential because, if the initialiser of the original subclass receives another object from the superclass initialiser, the new object needs to have enough memory allocated, and the same initial instance variable layout, as the original object, or assigning values into it may overwrite memory that's not part of the initialised object ... causing a crash or other runtime problems.

So, to correct our example, we should only return the special object if it is a subclass of the original object  ...

       if (level > wizardLevel && [crownOfTheEmperor isOwned] == NO
         && [crownOfTheEmperor isKindOfClass: [self class]] == YES)
         {
           RELEASE(self);
           [crownOfTheEmperor setOwned: YES];
           self = RETAIN(crownOfTheEmperor);
         }

The isKindOfClass: method is used to test that the object we are intending to return is legitimate ... a subclass of whatever class the original item (self) allocated was.

All classes should have a single designated initialiser.  This is the initialisation method that any direct subclass should call in order to ensure that initialisation is done correctly.  The other initialisers for the class (if any) should call the designated initialier, and the designated initialiser should not call any other initialisers that could be overridden by subclasses.

Since the init method is defined in the root class (NSObject), it's quite likely that any class could be initialised by calling this method.  If init is not the designated initialiser for your class, you should therefore write an implementation of init which does call the designated initialiser ...

     - (id) init
     {
       self = [self initWithLevel: noviceLevel];
       return self;
     }

Often, convenience methods are provided to avoid the necessity of allocating and initialising objects as two separate operations. The most basic of these is the +new method provided by the NSObject class.  This is simply an alloc followed by an init.

More sophisticated methods combine allocation, initialisation, and autoreleasing of objects.  These methods return objects which have been added to the current autorelease pool (see later in this chapter for details).  By convention, these methods have names beginning with something like the name of the class ...

     + (Crown*) crown
     {
       return AUTORELEASE([[self alloc] init]);
     }
     + (Crown*) crownWithLevel: (CharacterLevel)level
     {
       return AUTORELEASE([[self alloc] initWithLevel: level]);
     }

You handle deallocation of your objects by writing a dealloc method.  The last thing that this method needs to do is call the dealloc method of the superclass ... since it is normally the deallocation method of the root class that actually frees the memory used by the object.

The dealloc method is analogous to the destructor in a C++ class but, as with initialisation, the Objective-C language does not call this method for you, and you must explicitly call it (or refrain from calling it perhaps if you are caching the object for latert re-use).  Often, if you have not allocated memory or olther objects as instance variables in your object, you don't have to write a dealloc method, as the method in the superclass will do.

     @implementation	Crown
     - (void) dealloc
     {
       if (self == crownOfTheEmperor)
         {
           /*
            * The crown of the emperor can not be destroyed ... but it
            * can be made available for someone else to find.
            */
           [crownOfTheEmperor setOwned: NO];
         }
       else
         {
           // Release instance variables here.
           [super dealloc];
         }
     }
     @end

Protocols
=========

We use tweo types of protocol in Objective-C ... informal protocols, where we document methods to which objects will respond, and specify how they should behave, and formal protocols, where we provide a list of methods that an object will support in a format where the compiler can check things, and the runtime can also check that an object conforms to the protocol.  Informal protocols are merely convention, but are useful where we want to say that some system will work as long as it (or its delegate) implements some subset of a group of methods.  Formal protocols are more use when we want the compiler or runtime to check that an object implements all of a group of methods itsself.

  * The formal protocol provides a mechanism similar to the Java interface, in that it specifies an API to which instances of a class must conform. The Objective-C language provides mechanisms for checking that a class conforms to one or more protocols at compile time, while the runtime can chjeck that an object conforms to a protocol at runtime.  Protocols form an inheritance hierarchy much like that of classes.

     A particularly important use of protocols is in defining the methods that an object in a remote process can respond to ... by setting the protocol used by a local proxy object, you can avoid having to send messages to the remote process to check what methods are available - you can simply check the local protocol object.

       - Syntax

          A protocol is declared as a series of method declarations, just like a class interface.  The difference is that a protocol declaration begins with @protocol rather than @class, and has an optional super protocol specified in angle brackets.

          Another difference is that within a protocol declaration, certain additional type qualifiers used for Distributed Objects are valid -

               @protocol GameServer
               - (oneway void) handleClient: (id)client event:
                   (in bycopy NSData*) event;
               - (BOOL) registerClient: (id)client byName:
                   (in bycopy NSString*) name;
               @end

               @protocol MasterServer <GameServer>
               - (oneway void) systemShutdownBy: (id)client;
               @end

       - Protocol Objects

       - Conforming to a Protocol

          An object is said to conform to a protocol if it implements all the methods listed in that protocol.  The NSObject class provides a method for runtime testing to see if an object conforms to a protocol -

               if ([anObject conformsToProtocol: aProtocol] == YES)
                 {
                   // We can go ahead and use the object.
                 }
               else
                 {
                   NSLog(@"Object of class %@ ignored ... does not conform to
                     protocol", NSStringFromClass([anObject class]));
                 }

       - Type checking

       - Protocols within Protocols

       - Referring to Other Protocols

  * Informal Protocols

       - What are they, syntax

       - Example: delegates

Memory Management
=================

There are three forms of memory management available in Objective-C

  - Explicit
     You allocate objects using alloc, copy etc, and deallocate them when you have finished with them (using dealloc). This gives you complete control over memory management, and is highly efficient, but error prone.

  - Retain count
     You use the OpenStep retain/release mechanism, allong with autorelease pools which provide a degree of automated memory management.  This gives a good degree of control over memory management, but requires some care in following simple rules.  It's pretty efficient.

  - Garbage collection
     You build the GNUstep base library with garbage collection, and link with the Boehm GC library ... then never bother about releasing/deallocating memory.  This requires a slightly different approach to programming ... you need to take care about what happens when objects are deallocated ... but don't need to worry about deallocating them.

The recommended approach is to use some standard macros defined in NSObject.h which encapsulate the retain/release/autorelease mechanism, but which permit efficient use of the garbage collection system if you build your software with that.

  * The standard OpenStep system of memory management employs retain counts. When an object is created, it has a retain count of 1.  When an object is retained, the retain count is incremented.  When it is released the retain count is decremented, and when the retain count goes to zero the object gets deallocated.

            Coin	*c = [[Coin alloc] initWithValue: 10];

            // Put coin in pouch,
            RETAIN(c);	// Calls 'retain' method (retain count now 2)
            // Remove coin from pouch
            RELEASE(c);	// Calls 'release' method (retain count now 1)
            // Drop in bottomless well
            RELEASE(c);	// Calls 'release' ... (retain count 0) then 'dealloc'

  * A simple retain/release mechanism is not very interesting ... so it's spiced up with autorelease pools.  You can use the AUTORELEASE macro to call the autorelease method, which adds an object to the current autorelease pool.  An autorelease pool simply maintains a reference to each object added to it, and for each addition, the autorelease pool will call the release method of the object when the pool is released.  So doing an AUTORELEASE is just the same as doing a RELEASE, but deferred until the current autorelease pool is deallocated.

  * The General Convention About the Owner

  * Special cases: copy, mutableCopy, new

  * Full example for instance variable

  * Using ASSIGN to keep instance variables

  * Avoiding Retain Cycles

  * Special examples: delegate, target

How Messaging Works
===================

Objective-C messaging requires three types of information:

  * The message receiver - this contains isa, an instance variable of type Class, which points to a structure containing links into the class hierarchy, information specifying instance variable layout for the object, and a dispatch table specifying what code should be executed for each supported message.

  * The message selector - this identifies the message, and is used to locate the excecutable code of the corresponding method by performing a lookup in the dispatch table of the receiving objects class.

  * The message arguments - these are simply passed to the method on the stack.

When you send a message like obj = [array objectAtIndex: i];, the compiler actually does several things for you -

  * It generates code to place the receiver (array) on the stack.

  * It builds a selector for the message named objectAtIndex: and generates code to put it on the stack.

  * It generates code to put the argument (i) on the stack.

  * It generates code to ask the Objective-C runtime library to look up the selector in the receiver, return the method implementation for that selector (this is just a C function), and call that method implementation.

When a method is executed, it therefore has the message arguments available to it on the stack, but also has two additional values - the receiver and the selector.  These additional hidden arguments are referred to in the source code by the names self and _cmd.

The process of looking up the method implementation in the receiver at runtime is known as dynamic binding.  This is part of what makes the language powerful and flexible, but it is inevitably (despite clever caching strategies used in the runtime library) a little slower than a simple function call in C.

Hacking for Efficiency
======================

  * Getting a Method Address (discussion about reasons why doing it, and where it makes sense to do it)

  * Getting an Object Data Structure (short discussion about why doing it)

NSString
========

The NSString class defines objects holding raw Unicode character streams or strings. Unicode is a 16bit worldwide standard used to define character sets for all spoken languages. In GNUstep parlance the Unicode character is of type unichar.

Creating NSString Static Instances
----------------------------------

A static instance is allocated at compile time. The creation of a static instance of NSString is achieved using the @"..." construct and a pointer:

     NSString *wasp = @"Brainstorm";

wasp is a variable that refers to an NSString object representing the ASCII string "Brainstorm".

NSString - +stringWithFormat:
-----------------------------

The class method stringWithFormat: may also be used to create instances of NSString, and broadly echoes the printf function in the C programming language. stringWithFormat: accepts a list of arguments whose processed result is placed in an NSString that becomes a return value as illustrated below:

     int		qos = 5;
     NSString	*gprschannel;

     gprschannel = [NSString stringWithFormat: @"The GPRS channel is %d",
                     qos];

The example will produce an NSString called gprschannel holding the string "The gprschannel is 5".

stringWithFormat: recognises the %@ conversion specification that is used to specify an additional NSString:

     NSString *one;
     NSString *two;

     one = @"Brainstorm";
     two = [NSString stringWithFormat: @"Our trading name is %@", one];

The example assigns the variable two the string "Our trading name is Brainstorm." The %@ specification can be used to output an object's description - as returned by the NSObject's -description), which is useful when debugging, as in:

     NSObject *obj = [anObject aMethod];

     NSLog (@"The method returned: %@", obj);

C String Conversion
-------------------

When a program needs to call a C library function it is useful to create an NSString from a standard ASCII C string (not fixed at compile time):

     char *function (void);

To create an NSString using the contents of the returned C string (from the above example), use the NSString class method stringWithCString::

     char *result;
     NSString *string;

     result = function ();
     string = [NSString stringWithCString: result];

To convert an NSString to a standard C ASCII string, use the cString method of the NSString class:

     char		*result;
     NSString	*string;

     string = @"Hi!";
     result = [string cString];

NSMutableString
---------------

NSStrings are immutable objects; meaning that once they are created, they cannot be modified. This results in optimised NSString code. To modify a string, use the subclass of NSString, called NSMutableString. Use a NSMutableString wherever a NSString could be used.

An NSMutableString responds to methods that modify the string directly - which is not possible with a generic NSString. To create a NSMutableStringuse stringWithFormat::

     NSString *name = @"Brainstorm";
     NSMutableString *str;
     str = [NSMutableString stringWithFormat: @"Hi!, %@", name];

While NSString's implementation of stringWithFormat: returns a NSString, NSMutableString's implementation returns an NSMutableString.

Note. Static strings created with the @"..." construct are always immutable.

NSMutableStrings are rarely used because to modify a string, you normally create a new string derived from an existing one.

A useful method of the NSMutableString class is appendString:, which takes an NSString argument, and appends it to the receiver:

     NSString	*name = @"Brainstorm";
     NSString	*greeting = @"Hello";
     NSMutableString	*s;

     s = AUTORELEASE ([NSMutableString new]);
     [s appendString: greeting];
     [s appendString: @", "];
     [s appendString: name];

This code produces the same result as:

     NSString *name = @"Brainstorm";
     NSString *greeting = @"Hello";
     NSMutableString *s;

     s = [NSMutableString stringWithFormat: @"%@, %@", greeting, name];

Reading and Saving Strings
--------------------------

The the GNUstep base library has numerous string manipulation features, and among their most notable are those relating to writing/reading strings to/from files. To write the contents of a string to a file, use the writeToFile:atomically: method:

     #include <Foundation/Foundation.h>

     int
     main (void)
     {
       CREATE_AUTORELEASE_POOL(pool);
       NSString *name = @"This string was created by GNUstep";

       if ([name writeToFile: @"/home/nico/testing" atomically: YES])
         {
           NSLog (@"Success");
         }
       else
         {
           NSLog (@"Failure");
         }
       RELEASE(pool);
       return 0;
     }

writeToFile:atomically: returns YES for success, and NO for failure. If the atomically flag is YES, then the library first writes the string into a file with a temporary name, and, when the writing has been successfully done, renames the file to the specified filename. This prevents erasing the previous version of filename unless writing has been successful. This is a useful feature, which should be enabled.

To read the contents of a file into a string, use stringWithContentsOfFile:, as shown in the following example that reads @"/home/Brainstorm/test":

     #include <Foundation/Foundation.h>

     int
     main (void)
     {
       CREATE_AUTORELEASE_POOL(pool);
       NSString *string;
       NSString *filename = @"/home/nico/test";

       string = [NSString stringWithContentsOfFile: filename];
       if (string == nil)
         {
           NSLog (@"Problem reading file %@", filename);
           /*
            * <missing code: do something to manage the error...>
            * <exit perhaps ?>
            */
         }

       /*
        * <missing code: do something with string...>
        */

       RELEASE(pool);
       return 0;
     }