Skip to content

Instantly share code, notes, and snippets.

@markd2
Created June 6, 2013 14:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markd2/5722110 to your computer and use it in GitHub Desktop.
Save markd2/5722110 to your computer and use it in GitHub Desktop.
Bake a NSInvocation
#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