Skip to content

Instantly share code, notes, and snippets.

@Akhrameev
Forked from enigmaticape/part1.m
Created May 16, 2018 12:12
Show Gist options
  • Save Akhrameev/f8cd4d72343d933a68a18ef1d24e3f2f to your computer and use it in GitHub Desktop.
Save Akhrameev/f8cd4d72343d933a68a18ef1d24e3f2f to your computer and use it in GitHub Desktop.
You want to use NSObject performSelector with multiple parameters, but you can't ? (1)
- ( id ) methodWithOneParam:( id ) theParam {
// Do amazing stuff
return @"Srsly, Amazing!";
}
- ( id ) methodWithFirst:( id ) firstParam
andSecond:( id ) secondParam
{
// Do doubly amazing stuff
return @"Even Amazinger";
}
- ( id ) methodWithFirst:( id ) firstParam
andSecond:( id ) secondParam
andThird:( id ) thirdParam
{
// Do thricely amazing stuff that will certainly rock.
return @"MOAR AMAZINGER-ER!";
}
id first = nil;
id second = nil;
id third = nil;
id result = nil;
// easy peasy to do the first one.
SEL singleParamSelector = @selector(methodWithOneParam:);
result = [self performSelector:singleParamSelector // https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html
withObject:first];
NSLog(@"%@", result);
/*
Let's get a bit trickier and get the selector signature
from a string this tine
*/
SEL doubleParamSelector
= NSSelectorFromString(@"methodWithFirst:andSecond:");
result = [self performSelector: doubleParamSelector
withObject: first
withObject: second];
NSLog(@"%@", result);
- ( id ) boringMethod:( NSDictionary *) args {
id first = [args objectForKey:@"first" ];
id second = [args objectForKey:@"second"];
id third = [args objectForKey:@"third" ];
return @"Whatever";
}
NSInvocation * invocation; // https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/DistrObjects/Tasks/invocations.html#//apple_ref/doc/uid/20000744-CJBBACJH
NSMethodSignature * methSig; // http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSMethodSignature_Class/Reference/Reference.html
SEL triParamSelector;
/*
We need both a selector and a method signature,
they are different. A method signature contains
information about the number and types of arguments
a method takes, whereas a selector is just a name.
*/
triParamSelector = @selector(methodWithFirst:andSecond:andThird:);
methSig = [self methodSignatureForSelector: triParamSelector];
invocation = [NSInvocation invocationWithMethodSignature: methSig];
/*
Set the target (the object to invoke the
selector on) and the selector to invoke
*/
[invocation setSelector: triParamSelector];
[invocation setTarget: self];
/*
Now we have to set up the arguments. Note that we
have to start from 2, because there are two 'hidden'
arguments, which we'll get to shortly
*/
[invocation setArgument: &first atIndex: 2];
[invocation setArgument: &second atIndex: 3];
[invocation setArgument: &third atIndex: 4];
/*
Now make the call and get the returned value.
*/
[invocation invoke];
[invocation getReturnValue: &result];
NSLog(@"NSInvocation : %@", result);
SEL betterWaySelector
= NSSelectorFromString(@"methodWithFirst:andSecond:andThird:");
IMP methodImplementation // https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html
= [self methodForSelector: betterWaySelector];
result = methodImplementation( self,
betterWaySelector,
first,
second,
third );
NSLog(@"methodForSelector : %@", result);
SEL evenBetterWay
= NSSelectorFromString(@"methodWithFirst:andSecond:andThird:");
result = objc_msgSend( self,
evenBetterWay,
first,
second,
third );
NSLog(@"objc_msgSend : %@", result);
- ( void ) beware:( float ) whoops {
NSLog(@"%f", whoops);
}
- ( float ) incrementFloat:( float ) digits {
return digits + 1.0;
}
- ( void ) carefulNow {
SEL selector = @selector(beware:);
IMP method = [self methodForSelector: selector];
float test = 123.456;
/* works, obvs */
[self beware: test];
/*
123.456001
*/
/* bork */
objc_msgSend( self, selector, test);
/*
0.000000
*/
/* bork */
method( self, selector, test );
/*
0.000000
*/
/* works */
((void (*) (id, SEL,float))method)(self,selector,test);
/*
123.456001
*/
/* works */
((void (*) (id, SEL, float))objc_msgSend)(self,selector,test);
/*
123.456001
*/
selector = @selector(incrementFloat:);
float result
= ((float (*)(id,SEL,float))objc_msgSend)(self,selector,test);
NSLog(@"%f", result);
/*
124.456001
*/
method = [self methodForSelector:selector];
result = ((float (*) (id, SEL, float))method)(self,selector,test);
NSLog(@"%f", result);
/*
124.456001
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment