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 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 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 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 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 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 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 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 | |
*/ | |
} | |
Reading this was... intense. Thanks for the overview! :)
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 qualify result
with __unsafe_unretained
or change result
to void*
and __bridge
cast result
, otherwise the program may crash. See NSInvocation getReturnValue: called inside forwardInvocation: makes the returned object call dealloc:
.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Demo code for an article on the Enigmatic Ape Blog at http://www.enigmaticape.com/coding/objc-invoking-a-selector-with-multiple-parameters/