Skip to content
This repository
Fetching contributors…

Cannot retrieve contributors at this time

file 120 lines (100 sloc) 4.019 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
//
// Operation.m
// Frank
//
// Created by phodgson on 6/27/10.
// Copyright 2010 ThoughtWorks. See NOTICE file for details.
//

#import "Operation.h"


@implementation Operation

- (id) initFromJsonRepresentation:(NSDictionary *)operationDict {
self = [super init];
if (self != nil) {
_selector = NSSelectorFromString( [operationDict objectForKey:@"method_name"] );
_arguments = [[operationDict objectForKey:@"arguments"] retain];
}
return self;
}

- (void) dealloc
{
[_arguments release];
[super dealloc];
}

- (NSString *) description {
return NSStringFromSelector(_selector);
}

- (BOOL) appliesToObject:(id)target {
return [target respondsToSelector:_selector];
}

- (void)castNumber:(NSNumber *)number toType:(const char*)objCType intoBuffer:(void *)buffer{
// specific cases should be added here as needed
if( !strcmp(objCType, @encode(int)) ){
*((int *)buffer) = [number intValue];
}else if( !strcmp(objCType, @encode(uint)) ){
*((uint *)buffer) = [number unsignedIntValue];
}else if( !strcmp(objCType, @encode(double)) ){
*((double *)buffer) = [number doubleValue];
} else if ( !strcmp(objCType, @encode(char)) ) {
*((char*)buffer) = [number charValue];
} else if ( !strcmp(objCType, @encode(float)) ){
*((float *)buffer) = [number floatValue];
} else {
NSLog(@"Didn't know how to convert NSNumber to type %s", objCType);
}
}

- (id) applyToObject:(id)target {
NSMethodSignature *signature = [target methodSignatureForSelector:_selector];
NSUInteger requiredNumberOfArguments = signature.numberOfArguments - 2; // Indices 0 and 1 indicate the hidden arguments self and _cmd, respectively
if( requiredNumberOfArguments != [_arguments count] )
#if TARGET_OS_IPHONE
[NSException raise:@"wrong number of arguments"
format:@"%@ takes %i arguments, but %i were supplied", NSStringFromSelector(_selector), requiredNumberOfArguments, [_arguments count] ];
#else
        [NSException raise:@"wrong number of arguments"
                    format:@"%@ takes %lu arguments, but %lu were supplied", NSStringFromSelector(_selector), requiredNumberOfArguments, [_arguments count] ];
#endif

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:_selector];

NSInteger index = 2; // Indices 0 and 1 indicate the hidden arguments self and _cmd, respectively
for( id arg in _arguments ) {
if( [arg isKindOfClass:[NSNumber class]] ){
            const char* argumentType = [signature getArgumentTypeAtIndex:index];
            
            if ( !strcmp(argumentType, @encode(id)) ) {
                [invocation setArgument:&arg atIndex:index];
            } else {
                char buffer[10];
                [self castNumber:arg toType:argumentType intoBuffer:buffer];
                [invocation setArgument:buffer atIndex:index];
            }
} else {
[invocation setArgument:&arg atIndex:index];
}
index++;
}

[invocation invokeWithTarget:target];

const char *returnType = signature.methodReturnType;

id returnValue;
if( !strcmp(returnType, @encode(void)) ) {
returnValue = nil;
    }
else if( !strcmp(returnType, @encode(id)) ) { // retval is an objective c object
[invocation getReturnValue:&returnValue];
} else {
// handle primitive c types by wrapping them in an NSValue

NSUInteger length = [signature methodReturnLength];
void *buffer = (void *)malloc(length);
[invocation getReturnValue:buffer];

// for some reason using [NSValue valueWithBytes:returnType] is creating instances of NSConcreteValue rather than NSValue, so
//I'm fudging it here with case-by-case logic
if( !strcmp(returnType, @encode(BOOL)) ) {
returnValue = [NSNumber numberWithBool:*((BOOL*)buffer)];
}else if( !strcmp(returnType, @encode(NSInteger)) ) {
returnValue = [NSNumber numberWithInteger:*((NSInteger*)buffer)];
} else {
returnValue = [NSValue valueWithBytes:buffer objCType:returnType];
}
        
        free(buffer);
}
    
return returnValue;
}

@end
Something went wrong with that request. Please try again.