Target.m
author Jens Alfke <jens@mooseyard.com>
Fri May 02 12:49:43 2008 -0700 (2008-05-02)
changeset 7 59addced5e2a
parent 1 e55a17cdabd2
child 8 5588347dfcbd
permissions -rw-r--r--
Added URLUtils. Rewrote Target.
jens@0
     1
//
jens@0
     2
//  Target.m
jens@0
     3
//  MYUtilities
jens@0
     4
//
jens@0
     5
//  Created by Jens Alfke on 2/11/08.
jens@0
     6
//  Copyright 2008 Jens Alfke. All rights reserved.
jens@0
     7
//
jens@0
     8
jens@0
     9
#import "Target.h"
jens@0
    10
jens@0
    11
jens@7
    12
@implementation MYTarget
jens@7
    13
jens@7
    14
jens@7
    15
- (id) initWithReceiver: (id)receiver action: (SEL)action
jens@0
    16
{
jens@7
    17
    self = [super init];
jens@7
    18
    if( self ) {
jens@7
    19
        NSMethodSignature *sig = [receiver methodSignatureForSelector: action];
jens@7
    20
        CAssert(sig,@"%@<%p> does not respond to %@",[receiver class],receiver,NSStringFromSelector(action));
jens@7
    21
        CAssert(sig.numberOfArguments==3,
jens@7
    22
               @"-[%@ %@] can't be used as a target because it takes >1 param",
jens@7
    23
               [receiver class],NSStringFromSelector(action));
jens@7
    24
        CAssert(0==strcmp([sig getArgumentTypeAtIndex: 2],"@"),
jens@7
    25
               @"-[%@ %@] can't be used as a target because it takes a non-object param",
jens@7
    26
               [receiver class],NSStringFromSelector(action));
jens@7
    27
        NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sig];
jens@7
    28
        inv.target = receiver;
jens@7
    29
        inv.selector = action;
jens@7
    30
        _invocations = [inv retain];
jens@7
    31
    }
jens@7
    32
    return self;
jens@0
    33
}
jens@0
    34
jens@7
    35
+ (MYTarget*) targetWithReceiver: (id)receiver action: (SEL)action
jens@7
    36
{
jens@7
    37
    return [[[self alloc] initWithReceiver: receiver action: action] autorelease];
jens@7
    38
}
jens@0
    39
jens@7
    40
- (void) dealloc
jens@7
    41
{
jens@7
    42
    [_invocations release];
jens@7
    43
    [super dealloc];
jens@7
    44
}
jens@7
    45
jens@7
    46
jens@7
    47
- (NSArray*) invocations
jens@7
    48
{
jens@7
    49
    NSMutableArray *invocations = $castIf(NSMutableArray,_invocations);
jens@7
    50
    if( ! invocations )
jens@7
    51
        invocations = [NSMutableArray arrayWithObject: _invocations];
jens@7
    52
    return invocations;
jens@7
    53
}
jens@7
    54
jens@7
    55
jens@7
    56
- (NSString*) description
jens@7
    57
{
jens@7
    58
    NSMutableString *desc = [NSMutableString stringWithFormat: @"%@{", self.class];
jens@7
    59
    BOOL first = YES;
jens@7
    60
    for( NSInvocation *inv in self.invocations ) {
jens@7
    61
        if( first )
jens@7
    62
            first = NO;
jens@7
    63
        else
jens@7
    64
            [desc appendString: @", "];
jens@7
    65
        [desc appendFormat: @"-[%@ %s]", [inv.target class], inv.selector];
jens@7
    66
    }
jens@7
    67
    [desc appendString: @"}"];
jens@7
    68
    return desc;
jens@7
    69
}
jens@7
    70
jens@7
    71
jens@7
    72
static BOOL equalInvocations( NSInvocation *a, NSInvocation *b )
jens@7
    73
{
jens@7
    74
    return a.target==b.target && a.selector==b.selector;
jens@7
    75
}
jens@7
    76
jens@7
    77
jens@7
    78
- (BOOL) isEqual: (MYTarget*)t
jens@7
    79
{
jens@7
    80
    if( ! [t isKindOfClass: [self class]] )
jens@7
    81
        return NO;
jens@7
    82
    if( [_invocations isKindOfClass: [NSInvocation class]] && [t->_invocations isKindOfClass: [NSInvocation class]] )
jens@7
    83
        return equalInvocations(_invocations,t->_invocations);
jens@7
    84
    NSArray *myInvocations = self.invocations, *itsInvocations = t.invocations;
jens@7
    85
    unsigned n = myInvocations.count;
jens@7
    86
    if( n != itsInvocations.count )
jens@7
    87
        return NO;
jens@7
    88
    for( int i=0; i<n; i++ )
jens@7
    89
        if( ! equalInvocations( [myInvocations objectAtIndex: i],
jens@7
    90
                                [itsInvocations objectAtIndex: i] ) )
jens@7
    91
            return NO;
jens@7
    92
    return YES;
jens@7
    93
}
jens@7
    94
jens@7
    95
jens@7
    96
- (void) addTarget: (MYTarget*)target
jens@7
    97
{
jens@7
    98
    setObj(&_invocations,[self invocations]);
jens@7
    99
    [_invocations addObjectsFromArray: target.invocations];
jens@7
   100
}
jens@7
   101
jens@7
   102
jens@7
   103
static id invokeSingleTarget( NSInvocation *invocation, id param )
jens@0
   104
{
jens@1
   105
    id result = nil;
jens@7
   106
    if( invocation && invocation.target ) {
jens@7
   107
        [invocation retain];
jens@1
   108
        @try{
jens@7
   109
            [invocation setArgument: &param atIndex: 2];
jens@7
   110
            [invocation invoke];
jens@1
   111
            
jens@7
   112
            NSMethodSignature *sig = invocation.methodSignature;
jens@1
   113
            NSUInteger returnLength = sig.methodReturnLength;
jens@1
   114
            if( returnLength==0 ) {
jens@1
   115
                result = nil; // void
jens@0
   116
            } else {
jens@1
   117
                const char *returnType = sig.methodReturnType;
jens@1
   118
                if( returnType[0]=='@' ) {
jens@7
   119
                    [invocation getReturnValue: &result];
jens@1
   120
                } else {
jens@1
   121
                    UInt8 returnBuffer[returnLength];
jens@7
   122
                    [invocation getReturnValue: &returnBuffer];
jens@1
   123
                    result = [NSValue valueWithBytes: &returnBuffer objCType: returnType];
jens@1
   124
                }
jens@0
   125
            }
jens@1
   126
        }@finally{
jens@7
   127
            [invocation release];
jens@0
   128
        }
jens@1
   129
    }
jens@1
   130
    return result;
jens@0
   131
}
jens@7
   132
jens@7
   133
jens@7
   134
- (id) invokeWithSender: (id)sender
jens@7
   135
{
jens@7
   136
    id result;
jens@7
   137
    NSMutableArray *invocations = $castIf(NSMutableArray,_invocations);
jens@7
   138
    if( invocations ) {
jens@7
   139
        for( NSInvocation *invocation in invocations )
jens@7
   140
            result = invokeSingleTarget(invocation,sender);
jens@7
   141
    } else {
jens@7
   142
        result = invokeSingleTarget(_invocations,sender);
jens@7
   143
    }
jens@7
   144
    return result;
jens@7
   145
}
jens@7
   146
jens@7
   147
jens@7
   148
@end