Created
November 22, 2012 14:16
-
-
Save enigmaticape/4131386 to your computer and use it in GitHub Desktop.
sample code for a better performSelector (see comments for link)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* lots of easy to spot sentinel values */ | |
variadicFunction( 0x42, | |
DEADBEEF, OOOOF642, DEADBEEF, | |
B_yes, FACEF00D, | |
b_true, FACEF00D, | |
(char)0x42, CAFED00D, | |
aString, DEADBEEF, | |
DEADCAFEBEEFD00D ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int hax0rSomeInts( int n, ... ) { | |
va_list args; | |
va_start( args, n ); | |
int sum = 0; | |
for( int i = 0; i < n; i++ ) { | |
sum += *((int*)args); | |
args += sizeof(int); | |
} | |
va_end( args ); | |
return sum; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int DEADBEEF = 0xefbeadde; // DE AD BE EF | |
int FACEF00D = 0x0df0cefa; // FA CE F0 0D | |
float OOOOF642 = 123.000; // 00 00 F6 42 | |
BOOL B_yes = YES; // 01 | |
bool b_true = true; // 01 | |
void* CAFED00D = (void*)0x0dd0feca; // CA FE D0 0D | |
long long DEADCAFEBEEFD00D // DE AD CA FE BE EF D0 0D | |
= 0x0dd0efbefecaadde; | |
NSString * aString = @"A string"; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (NSValue *) invokeSelector:(SEL)selector, ... { | |
va_list args; | |
va_start( args, selector ); | |
NSMethodSignature * signature | |
= [self methodSignatureForSelector:selector]; | |
NSInvocation * invocation | |
= [NSInvocation invocationWithMethodSignature:signature]; | |
[invocation setTarget:self]; | |
[invocation setSelector:selector]; | |
NSUInteger arg_count = [signature numberOfArguments]; | |
for( NSInteger i = 0; i < arg_count - 2; i++ ) { | |
/* we now need to check a few things, | |
firstly whether we have a float | |
*/ | |
if( strcmp( [signature getArgumentTypeAtIndex: 2 + i ], "f") == 0 ) { | |
/* If we do have a float, we need to get the value, | |
and then convert it back to a float ... | |
*/ | |
double doublvalue = va_arg( args, typeof(double) ); | |
float floatvalue = (float)doublvalue; | |
/* ... before we copy it into position | |
*/ | |
[invocation setArgument:&floatvalue atIndex: 2 + i ]; | |
/* Now we increment the pointer past the | |
argument so it points at the next one | |
*/ | |
args += sizeof( double ); | |
} | |
else { | |
/* if it isn't a float, we want to find out | |
what size it is, bearing in mind the whole | |
promotion thingamajig | |
*/ | |
NSUInteger size; | |
NSGetSizeAndAlignment( [signature getArgumentTypeAtIndex: 2 + i ], | |
&size, | |
NULL ); | |
NSUInteger actual_size = size >= 4 ? size : 4; | |
/* since our single byte promoted values will be in | |
the first byte, this should be OK, just pass the | |
pointer and let NSInvocation copy one (or however many) | |
bytes | |
*/ | |
[invocation setArgument:args atIndex: 2 + i ]; | |
/* But we *do* need to make sure we increment the | |
pointer by enough bytes | |
*/ | |
args += actual_size; | |
} | |
} | |
/* and in theory, that should be enough for us | |
to do the invocation | |
*/ | |
[invocation invoke]; | |
va_end( args ); // As far as we know, this is a no op. Hmmm. | |
/* | |
for the moment, we'll just return an NSValue again | |
since there's no particulalrly nice way to return an | |
arbitrary type | |
*/ | |
NSValue * ret_val = nil; | |
NSUInteger ret_size = [signature methodReturnLength]; | |
if( ret_size > 0 ) { | |
void * ret_buffer = malloc( ret_size ); | |
[invocation getReturnValue:ret_buffer]; | |
ret_val = [NSValue valueWithBytes:ret_buffer | |
objCType:[signature methodReturnType]]; | |
free(ret_buffer); | |
} | |
return ret_val; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- ( void ) invokeSelector:( SEL )selector | |
withReturnValue:( void* ) retval, ... { | |
va_list args; | |
va_start( args, selector ); | |
/* all the same stuff | |
.... | |
.... | |
*/ | |
va_end( args ); // As far as we know, this is a no op. Hmmm. | |
/* | |
OK, this time, we'll copy the value straight out, like this, | |
and NSValue is all gone. | |
*/ | |
if ( [signature methodReturnLength] > 0 ) { | |
[invocation getReturnValue:retval]; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
TestObj * testobj = [[TestObj alloc] init]; | |
SEL selector | |
= @selector(printString:aBOOL:aBool:aChar:anInt:andIncrement:); | |
float aFloat = 123.456; | |
int anInt = 42; | |
BOOL aBOOL = YES; | |
bool aBool = YES; | |
char aChar = 'z'; | |
NSString * aString = @"The answer is"; | |
NSValue * result; | |
float floatresult; | |
float anotherfloat = 0; | |
NSLog(@"%@ : %@ : %@ : %c : %i : (%f)", | |
aString, | |
aBOOL ? @"YES" : @"NO", | |
aBool ? @"true" : @"fale", | |
aChar, | |
anInt, | |
aFloat | |
); | |
result = [testobj invokeSelector:selector, | |
aString, | |
aBOOL, | |
aBool, | |
aChar, | |
anInt, | |
aFloat | |
]; | |
[result getValue: &floatresult]; | |
NSLog(@"%f", floatresult); | |
[testobj invokeSelector:selector withReturnValue:&anotherfloat, | |
aString, | |
aBOOL, | |
aBool, | |
aChar, | |
anInt, | |
aFloat | |
]; | |
NSLog(@"%f", anotherfloat); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "TestObj.h" | |
@implementation TestObj | |
-(float) printString:(NSString*) aString | |
aBOOL:(BOOL) aBOOL | |
aBool:(bool) aBool | |
aChar:(char) aChar | |
anInt:(int) anInt | |
andIncrement:(float) aFloat | |
{ | |
NSLog(@"%@ : %@ : %@ : %c : %i : (%f)", | |
aString, | |
aBOOL ? @"YES" : @"NO", | |
aBool ? @"true" : @"false", | |
aChar, | |
anInt, | |
aFloat | |
); | |
return aFloat + 1.0; | |
} | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typedef struct { | |
/* offset into reg_save_area where | |
the next available general purpose | |
argument is located | |
*/ | |
unsigned int gp_offset; | |
/* offset into reg_save_area where | |
the next available floating point | |
argument is located | |
*/ | |
unsigned int fp_offset; | |
/* pointer to start of any arguments | |
which were passed on the stack | |
*/ | |
void *overflow_arg_area; | |
/* pointer to the area of memory to which | |
the registers have been saved by the | |
variadic function's prolougue. | |
*/ | |
void *reg_save_area; | |
} va_list[1]; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void variadicFunction(int n, ... ) { | |
va_list args; | |
va_start(args, n); | |
/* do | |
some | |
stuff | |
*/ | |
va_end( args ); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int sumSomeInts( int n, ... ) { | |
va_list args; | |
va_start( args, n ); | |
int sum = 0; | |
for( int i = 0; i < n; i++ ) { | |
sum += va_arg( args, int ); | |
} | |
va_end( args ); | |
return sum; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
From a short series on doing mo better performSelector type stuff, explanatory post on the Enigmatic Ape blog at http://www.enigmaticape.com/blog/better-performselector-evil-fun-with-va_args/