Target.m
author Jens Alfke <jens@mooseyard.com>
Sun May 10 18:57:43 2009 -0700 (2009-05-10)
changeset 29 8874aff14cc9
parent 11 e5976864dfe9
permissions -rw-r--r--
* Added kv*Set utility functions for handling KV grunge when mutating an NSSet property.
* Change CFMakeCollectable to NSMakeCollectable.
     1 //
     2 //  Target.m
     3 //  MYUtilities
     4 //
     5 //  Created by Jens Alfke on 2/11/08.
     6 //  Copyright 2008 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "Target.h"
    10 #import "Logging.h"
    11 #import "Test.h"
    12 
    13 
    14 @implementation MYTarget
    15 
    16 
    17 - (id) initWithReceiver: (id)receiver action: (SEL)action
    18 {
    19     self = [super init];
    20     if( self ) {
    21         NSMethodSignature *sig = [receiver methodSignatureForSelector: action];
    22         CAssert(sig,@"%@<%p> does not respond to %@",[receiver class],receiver,NSStringFromSelector(action));
    23         CAssert(sig.numberOfArguments==3,
    24                @"-[%@ %@] can't be used as a target because it takes >1 param",
    25                [receiver class],NSStringFromSelector(action));
    26         CAssert(0==strcmp([sig getArgumentTypeAtIndex: 2],"@"),
    27                @"-[%@ %@] can't be used as a target because it takes a non-object param",
    28                [receiver class],NSStringFromSelector(action));
    29         NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sig];
    30         inv.target = receiver;
    31         inv.selector = action;
    32         _invocations = [inv retain];
    33     }
    34     return self;
    35 }
    36 
    37 + (MYTarget*) targetWithReceiver: (id)receiver action: (SEL)action
    38 {
    39     return [[[self alloc] initWithReceiver: receiver action: action] autorelease];
    40 }
    41 
    42 - (void) dealloc
    43 {
    44     [_invocations release];
    45     [super dealloc];
    46 }
    47 
    48 
    49 - (NSArray*) invocations
    50 {
    51     NSMutableArray *invocations = $castIf(NSMutableArray,_invocations);
    52     if( ! invocations )
    53         invocations = [NSMutableArray arrayWithObject: _invocations];
    54     return invocations;
    55 }
    56 
    57 
    58 - (NSString*) description
    59 {
    60     NSMutableString *desc = [NSMutableString stringWithFormat: @"%@{", self.class];
    61     BOOL first = YES;
    62     for( NSInvocation *inv in self.invocations ) {
    63         if( first )
    64             first = NO;
    65         else
    66             [desc appendString: @", "];
    67         [desc appendFormat: @"-[%@ %s]", [inv.target class], inv.selector];
    68     }
    69     [desc appendString: @"}"];
    70     return desc;
    71 }
    72 
    73 
    74 static BOOL equalInvocations( NSInvocation *a, NSInvocation *b )
    75 {
    76     return a.target==b.target && a.selector==b.selector;
    77 }
    78 
    79 
    80 - (BOOL) isEqual: (MYTarget*)t
    81 {
    82     if( ! [t isKindOfClass: [self class]] )
    83         return NO;
    84     if( [_invocations isKindOfClass: [NSInvocation class]] && [t->_invocations isKindOfClass: [NSInvocation class]] )
    85         return equalInvocations(_invocations,t->_invocations);
    86     NSArray *myInvocations = self.invocations, *itsInvocations = t.invocations;
    87     NSUInteger n = myInvocations.count;
    88     if( n != itsInvocations.count )
    89         return NO;
    90     for( NSUInteger i=0; i<n; i++ )
    91         if( ! equalInvocations( [myInvocations objectAtIndex: i],
    92                                 [itsInvocations objectAtIndex: i] ) )
    93             return NO;
    94     return YES;
    95 }
    96 
    97 
    98 - (void) addTarget: (MYTarget*)target
    99 {
   100     setObj(&_invocations,[self invocations]);
   101     [_invocations addObjectsFromArray: target.invocations];
   102 }
   103 
   104 
   105 static id invokeSingleTarget( NSInvocation *invocation, id param )
   106 {
   107     id result = nil;
   108     if( invocation && invocation.target ) {
   109         [invocation retain];
   110         @try{
   111             [invocation setArgument: &param atIndex: 2];
   112             [invocation invoke];
   113             
   114             NSMethodSignature *sig = invocation.methodSignature;
   115             NSUInteger returnLength = sig.methodReturnLength;
   116             if( returnLength==0 ) {
   117                 result = nil; // void
   118             } else {
   119                 const char *returnType = sig.methodReturnType;
   120                 if( returnType[0]=='@' ) {
   121                     [invocation getReturnValue: &result];
   122                 } else {
   123                     UInt8 returnBuffer[returnLength];
   124                     [invocation getReturnValue: &returnBuffer];
   125                     result = [NSValue valueWithBytes: &returnBuffer objCType: returnType];
   126                 }
   127             }
   128         }@finally{
   129             [invocation release];
   130         }
   131     }
   132     return result;
   133 }
   134 
   135 
   136 - (id) invokeWithSender: (id)sender
   137 {
   138     id result;
   139     NSMutableArray *invocations = $castIf(NSMutableArray,_invocations);
   140     if( invocations ) {
   141         result = nil;
   142         for( NSInvocation *invocation in invocations )
   143             result = invokeSingleTarget(invocation,sender);
   144     } else {
   145         result = invokeSingleTarget(_invocations,sender);
   146     }
   147     return result;
   148 }
   149 
   150 
   151 @end
   152 
   153 
   154 /*
   155  Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   156  
   157  Redistribution and use in source and binary forms, with or without modification, are permitted
   158  provided that the following conditions are met:
   159  
   160  * Redistributions of source code must retain the above copyright notice, this list of conditions
   161  and the following disclaimer.
   162  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   163  and the following disclaimer in the documentation and/or other materials provided with the
   164  distribution.
   165  
   166  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   167  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   168  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   169  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   170  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   171   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   172  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   173  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   174  */