Created
November 14, 2012 19:59
-
-
Save enigmaticape/4074403 to your computer and use it in GitHub Desktop.
You want to use NSObject performSelector with multiple parameters, but you can't ? (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
- ( 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!"; | |
} |
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
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); |
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
- ( id ) boringMethod:( NSDictionary *) args { | |
id first = [args objectForKey:@"first" ]; | |
id second = [args objectForKey:@"second"]; | |
id third = [args objectForKey:@"third" ]; | |
return @"Whatever"; | |
} |
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
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); | |
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
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); |
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
SEL evenBetterWay | |
= NSSelectorFromString(@"methodWithFirst:andSecond:andThird:"); | |
result = objc_msgSend( self, | |
evenBetterWay, | |
first, | |
second, | |
third ); | |
NSLog(@"objc_msgSend : %@", result); |
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 ) 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
Cool, thanks for sharing. By the way, the blog link seems broken.
One thing to notice when you call
getReturnValue
to get an object under ARC is that you need to either qualifyresult
with__unsafe_unretained
or changeresult
tovoid*
and__bridge
castresult
, otherwise the program may crash. See NSInvocation getReturnValue: called inside forwardInvocation: makes the returned object call dealloc:.