_Dynamic Design Patterns in Objective-C_
by William Grosso


Listing One 
//  From the header file -- define a pointer to member function for a method 
    bool appBecameActiveCanBeCalled;
    id (* appBecameActive) (id, SEL, id);

// From the .m (code) file (and heavily annotated)
- (void) setDelegate: newDelegate
{
    SEL tokenizedMethodName; // the @selector compiler directive tokenizes 
                             // the method name. 
//  First, we check to see if we have a delegate and, if so, whether the new 
//  delegate is from the same class; if both these are true, just return. 
    if ((nil!=_internalDelegate) && ([newDelegate cisMemberOf: 
                                              [_internalDelegate class]))
    {
        _internalDelegate = [newDelegate retain];   //delegate won't be freed
return;
    }
// We need to explicitly check which methods our new delegate has implemented. 
    _internalDelegate = [newDelegate retain];  //ensure delegate won't be freed
    tokenizedMethodName=@selector(appBecameActive:);
    if (YES==[ newDelegate respondsTo: tokenizedMethodName])
    {
//  syntax is [object memberFunction: argumentOne tag: argument2 ...]; We now
//  know that the new delegate object implements appBecameActive. We will get 
//  function pointer (for speed, might be calling this function often and 
//  and therefore want to avoid rebinding the selector).  Usually, we wouldn't
//  get the function pointer. 
AppBecameActive=(id (*) (id,  SEL, id) 
[_internalDelegate methodFor: tokenizedMethodName];
        appBecameActiveCanBeCalled=YES;
    }
else
{
appBecameActiveCanBeCalled =NO;
    }
//  ....
}


Listing Two
//  code in main application
-  loadObscureClassFromDisk
{
//  Our goal is to find a requried class object (which we will return)

    Class classThatsNeeded;
//  Has it been loaded ? Try to find the class object using a wrapper 
//  function which encapsulates the run-time function objc_lookUpClass();
    classThatsNeeded =NXClassFromString("ObscureClassName");
    If (nil== classThatsNeeded)
    {
//  No class object. We need to load it. 
//  Build a path name, relative to where application was installed by 
//  concatenating a subdirectory name onto [[NXApp mainBundle] directory] 
        char * fullPathDirectory;
        ....
        NXBundle * bundleForClass =[[NXBundle alloc] initForDirectory: 
                                                          fullPathDirectory];
        classThatsNeeded=[ bundleForClass classNamed:"ObscureClassName"];
    }
    return classThatsNeeded;
}


Listing Three
//  code in an element
- (bool) accept: aVisitor
{
//  Protocols are like interfaces in javathey define a set of methods. 
//  Objects, when declared (in their header files), inherit from one concrete
//  class and multiple protocols. This accept method checks whether the 
//  visitor conformsTo (inherits from) a certain protocol declared earlier 
//  or if the visitor is of a particular class. 
    if (([aVisitor conformsTo: MyProtocol]) !! 
                                       ([aVisitor isKindOf: acceptableClass]))
    {
        return [aVisitor visit: self];
    }
    return NO;
}
//  code in a visitor
- visit: anElement
{
//  again, do type checking. Check whether element is an instance of a 
//  specific class; if that fails, whether it inherits from some other class. 
//  classOne and classTwo are declared previously. 
    if ([anElement isMemberOf: classOne])
    {
//  perform some sequence of actions
    }
    else if ([anElement isKindOf: classTwo])
    {
//  perform some sequence of actions
    }
return NO;
}

Listing Four
template <Class T> CommandObject
{
    private: 
        T& target
        void (T::memberFunctionToCall)();
    public:
        CommandObject(T& theTarget, void (T::theMemberFunctionToCall)());
        void Do();
}
//  comment: ask Don to finish this.


Listing Five
//  headers  --  Serializer implements
- (void) writeInt: (id) value;
- (void) writeFloat: (id) value;
- (void) writeDouble: (id) value
- (void) writeChar: (id) value
- (void) writeObject: (id) value

//  Serializable implements
- (void) serializeUsing: (Serializer *) serializerToUse;
- (void) initWithDeserializer: (Deserialier *) deserializerWithMyState;

//  Serializer implements
- (int) readInt;
- (float) readFloat;
- (double) readDouble;
- (char) readChar;
- (id) readObject;

//  from Serializer's Code
- (void) writeObject: (id) value
{
    if (YES==[self objectAlreadyWritten: value])
    {
//  The object thas already been serialized. We just store the 
//  internal uuid (so we can rebuild the object graph). 
        [self storeReferenceToObject: value];
    }
    else
    {
//  first log that we're storing the object.
        [self createReferenceFor: value];
        [self writeString: NSStringFromClass([[value class])];
        [value serializeUsing: self];
    }
}
//  from Deserializer's code
- (id) readObject
{
//  ....
//  Here we need to exhume a previously unknown object.
    Class classObjectForValue;
    id value;
classObjectForValue = NSClassFromString([self readNextString]);
    if (nil!= classObjectForValue)
    {
        value=[[ classObjectForValue alloc] initFromSerializer: self];
    }
    else
    {
//  Bad thing happened here. Raise an exception because our data is corrupt.
//      ...
    }
    return value;
}

Listing Six
//  header (.h) file
#import <foundation/foundation.h>
@interface CommandObject: NSObject
{
    id target;
    id argument;
    NSString * nameOfMethod;
    SEL selectorForMethod;
}
- (void) dealloc;
- init;
- (void) setArgumentObject:  newArgument;
- (void) setTargetObject:  newTarget;

//  Function overloading would make the next two methods more pleasant. 
- (void) setTargetMethodByString: (NSString *) methodName;  
- (void) setTargetMethodBySelector:  (SEL) methodSelector;
- (bool) do;
- (void) initWithCoder: (NSCoder *) decoder;
- (void) encodeWithCoder: (NSCoder *) encoder;  
@end

//  code (.m) file
#import "CommandObject.h"
@implementation CommandObject
- (void) dealloc
{
//  retain, release, and autorelease are all part of reference counting.
//  ref counting is in NEXTSTEP, but not part of the Objective-C spec.
//  When an object's ref count goes to zero, it is deallocated.
    [target autorelease];
    [argument autorelease];
    [nameOfMethod autorelease];
    [super dealloc];
    return;
}
- init
{
//  init is like a constructor. The object has already been 
//  allocated and needs to have its variables initialized. 
    [super init];
    nameOfMethod=argument=target=nil;   //always safe cause messages to nil
                        //don't cause problems. 
    return self;                //note that the return value of init has to be 
                        //specified, unlike the return value from a 
                        //C++ constructor. 
}
- (void) setArgumentObject:  newArgument
{
    if (nil!=argument)
    {
        [argument autorelease];
    }   
    argument=newArgument;
    [argument retain];
    return;
}
- (void) setTargetObject:  newTarget
{
    if (nil!=target)
    {
        [target autorelease];
    }   
   target=newTarget;
    [target retain];
    return;
}
- (void) setTargetMethodByString: (NSString *) methodName
{
    nameOfMethod = [methodName copy];   //make our own copy
                        //to guard against changes
    selectorForMethod= NSSelectorFromString (nameOfMethod);
    return;
}
- (void) setTargetMethodBySelector:  (SEL) methodSelector
{
selectorForMethod= methodSelector;
nameOfMethod= [NSStringFromSelector (selectorForMethod) retain];
    return;
}
- (bool) do
{
    if (YES==[target respondsTo: selectorForMethod])
    {
        [target perform: selectorForMethod];
        return YES;
    }
    return NO;
}
- (void) initWithCoder: (NSCoder *) decoder
{
//  From target, object, and nameOfMethod, we can get selector back (in fact,
//  we'll call function to do so). Hence, object graph can be fully restored. 
//  ....
}
- (void) encodeWithCoder: (NSCoder *) encoder
{
//  We write out three objects--target, argument,and nameOfMethod. 
//  this is just the "serialize" method discussed earlier.
//  ...
}
@end


