Reputation: 3370
Ok, here's what I have:
SEL propertySelector = NSSelectorFromString(keyPath);
if ([obj respondsToSelector:propertySelector]){
id propertyValue = [obj performSelector:propertySelector];
}
So, the keyPath
is a NSString
and it's used to pass the string name of a method. After that, I create a @selector
from that string using NSSelectorFromString()
and I check if the object (obj
) responds to that selector.
But now here's the problem, I want to get the returning value of the method that I want to call, but it seems like the code above doesn't work with type values like int
, NSInteger
, etc.. because I'm using id
for the propertyValue
(if I call the method above in the middle of another method, and the keyPath
is referencing a method that returns an int, the first method will stop being executed).
How can I receive the value of the method no matter what type it is?
Thanks!
Upvotes: 0
Views: 935
Reputation: 122439
If you know what you're doing, you can use objc_msgSend
directly:
NSInteger (*f)(id, SEL) = (NSInteger (*)(id, SEL))objc_msgSend;
SEL propertySelector = NSSelectorFromString(keyPath);
if ([obj respondsToSelector:propertySelector]){
NSInteger retVal = f(obj, propertySelector);
}
Upvotes: 1
Reputation: 64002
If you're accessing a property, you should definitely consider KVC, which boxes up the primitive into an NSNumber
for you.
NSInteger val = [[obj valueForKeyPath:keyPath] integerValue];
As for your literal question, the performSelector:
docs tell you what to do.
For methods that return anything other than an object, use
NSInvocation
.
Which looks like this:
NSInteger retVal;
SEL sel = NSSelectorFromString(keyPath);
NSMethodSignature * sig = [obj methodSignatureForSelector:sel];
NSInvocation * inv = [NSInvocation invocationWithMethodSignature:sig];
[inv setTarget:obj];
[inv setSelector:sel];
[inv invoke];
[inv getReturnValue:&retVal];
// Use retVal
Upvotes: 5
Reputation: 11016
The following works like a charm for me:
- (void)foo {
SEL propertySelector = NSSelectorFromString(@"doSomething");
if ([self respondsToSelector:propertySelector]){
id propertyValue = [self performSelector:propertySelector];
NSLog(@"%@", propertyValue);
}
}
- (NSNumber *)doSomething {
return @42;
}
Output is, as expected:
42
There could eventually be a problem if you method return type is not an object (and this seems to be the case based on your edit). From the doc:
performSelector:
Sends a specified message to the receiver and returns the result of the message. (required)
Return Value
An object that is the result of the message.
(emphasis on object).
If you try to use performSelector:
on a selector which return type is not a object, you will get an EXC_BAD_ACCESS
.
Which means you must change your return type and encapsulate the returned value in an object (eg. NSNumber
or NSValue
). Note that in the case of an int
or NSInteger
or other "number" types, this can be done by enclosing the value with @()
(for example return 3.2;
becomes return @(3.2);
).
Upvotes: 0