Created
June 6, 2013 14:54
-
-
Save markd2/5722110 to your computer and use it in GitHub Desktop.
Bake a NSInvocation
This file contains 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 <Foundation/Foundation.h> | |
// Wrap up a call to rangeOfCharacterFromSet:options:range: in an invocation. | |
// clang -g -Wall -framework Foundation -o invocation invocation.m | |
// Little utility to dump out a method signature. | |
static void printSignature (NSMethodSignature *signature) { | |
NSLog (@"%ld arguments", [signature numberOfArguments]); | |
for (NSUInteger i = 0; i < [signature numberOfArguments]; i++) { | |
NSLog (@"%ld -> %s", i, [signature getArgumentTypeAtIndex: i]); | |
} | |
NSLog (@"returning %s", [signature methodReturnType]); | |
} // printSignature | |
int main (void) { | |
@autoreleasepool { | |
// Make a call normally | |
// 11111111112222 | |
// 012345678901234567890123 | |
NSString *baseString = @"Why hello there, Hoover."; | |
// |-------------| | |
NSRange randomRange = (NSRange){5, 15}; | |
NSCharacterSet *set = [NSCharacterSet whitespaceCharacterSet]; | |
NSStringCompareOptions options = NSBackwardsSearch; | |
NSRange lastSpace = | |
[baseString rangeOfCharacterFromSet: set | |
options: options | |
range: randomRange]; | |
NSLog (@"%@", NSStringFromRange(lastSpace)); // returns {16, 1} | |
// Build an invocation | |
NSMethodSignature *rangeSignature = | |
[NSString instanceMethodSignatureForSelector: | |
@selector(rangeOfCharacterFromSet:options:range:)]; | |
NSInvocation *spaceFinder = | |
[NSInvocation invocationWithMethodSignature: rangeSignature]; | |
[spaceFinder retainArguments]; | |
[spaceFinder setTarget: baseString]; | |
[spaceFinder setSelector: @selector(rangeOfCharacterFromSet:options:range:)]; | |
[spaceFinder setArgument: &set atIndex: 2]; // target=0, selector=1 | |
[spaceFinder setArgument: &options atIndex: 3]; | |
[spaceFinder setArgument: &randomRange atIndex: 4]; | |
[spaceFinder invoke]; | |
NSRange anotherLastSpace; | |
[spaceFinder getReturnValue: &anotherLastSpace]; | |
NSLog (@"invocation result: %@", NSStringFromRange(anotherLastSpace)); | |
// Use the invocation on another object. | |
// 1111111111 | |
// 01234567890123456789 | |
NSString *secondString = @"I seem to be a verb!"; | |
// |-------------| | |
[spaceFinder setTarget: secondString]; | |
[spaceFinder invoke]; | |
NSRange yetAnotherLastSpace; | |
[spaceFinder getReturnValue: &yetAnotherLastSpace]; | |
NSLog (@"I seem to be a range: %@", NSStringFromRange(yetAnotherLastSpace)); | |
#if PLAYING_WITH_VARARG_METHOD | |
// Varargs aren't directly supported, but I _think_ you can construct an | |
// invocaton that fills in the arguments accordingly. | |
char *typeEncodings; | |
asprintf(&typeEncodings, "%s%s%s%s%s%s", | |
@encode(id), // self | |
@encode(SEL), // _cmd | |
@encode(id), // format string | |
@encode(int), // %d | |
@encode(char *), // %s | |
@encode(id)); // %@ | |
printf ("ook : %s\n", typeEncodings); | |
// Invoking varargs | |
NSMethodSignature *initWithFormatSignature = | |
[NSMethodSignature signatureWithObjCTypes: typeEncodings]; | |
free (typeEncodings); // asprintf dynamically allocates. | |
NSInvocation *formatInvocation = | |
[NSInvocation invocationWithMethodSignature: initWithFormatSignature]; | |
[formatInvocation retainArguments]; | |
printSignature (initWithFormatSignature); | |
NSString *target = [NSString alloc]; // we're deferring the init. | |
NSString *formatString = @"I am %d years old, and my name is %s, %@!"; | |
formatInvocation.target = target; | |
// crashing here - dunno if it's due to the half-alloc, or | |
// class clusterage, or if I'm just doing wrong. | |
formatInvocation.selector = @selector(initWithFormat:); | |
[formatInvocation setArgument: formatString atIndex: 2]; | |
int age = 4; | |
[formatInvocation setArgument: &age atIndex: 3]; | |
char *name = "bork"; | |
[formatInvocation setArgument: name atIndex: 4]; | |
NSString *interjection = @"Groovy!"; | |
[formatInvocation setArgument: interjection atIndex: 5]; | |
[formatInvocation invoke]; | |
NSString *finalString; | |
[formatInvocation getReturnValue: &finalString]; | |
NSLog (@"please? %@", finalString); | |
#endif // PLAYING_WITH_VARARG_METHOD | |
} | |
return 0; | |
} // main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment