Perform Selector Casting
casting, objective-c, performselector, reflection
Solution
The `performSelector` method only supports methods that return nothing or an object. This is covered in its documentation where it states:
For methods that return anything other than an object, use `NSInvocation`.
Your "hack" is just the correct way of calling a selector which returns a non-object.
The reason why it appears to work for integer and boolean methods is to do with the way values are returned by methods. The return type of `performSelector` is `id`, an object pointer type. Integer-like values; which includes `NSInteger`, `BOOL` and object pointers; are often returned in a general purpose register, however floating point values are usually returned in a floating point register. The compiler will always load the result from the register used for returning `id` values and then perform any action required by the cast. For integer and boolean values the loaded value is probably correct and the cast is a no-op in those cases, so everything (appears to) work. For floating point values the loaded value is incorrect - it is not the value the called method has returned as that is in a different register.
Note calling non-object, non-void, selectors with `performSelector` can cause memory issues under ARC - the compiler will usually warn if this might be the case.
The `NSInvocation` way of calling a selector works for non-object return types as one of its arguments is the method signature itself. Using the signature `NSInvocation` is able to determine the type of the return value and how it is returned, and therefore correctly return it to the caller.
HTH
Problem
There's a really strange behavior going on with float / double / CGFloat casting on the result of performSelector: Why does this work? ``` BOOL property = (BOOL)[self.object performSelector:@selector(boolProperty)]; NSInteger property = (NSInteger) [self.object performSelector:@selector(integerProperty)]; ``` And this doesn't ``` CGFloat property = (CGFloat) [self.object performSelector:@selector(floatProperty)]; ``` At first I tried to do this: ``` CGFloat property = [[self.object performSelector:@selector(floatProperty)] floatValue]; ``` But I ended up getting an EXC_BAD_ACCESS runtime error. I already figured out a hack to solve this issue but I would like to understand why it works with Integer and Bool and not with floating point types. My hack: ``` @implementation NSObject (AddOn) -(CGFloat)performFloatSelector:(SEL)aSelector { NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:aSelector]]; [invocation setSelector:aSelector]; [invocation setTarget:self]; [invocation invoke]; CGFloat f = 0.0f; [invocation getReturnValue:&f]; return f; } @end ``` Then: ``` CGFloat property = [self.object performFloatSelector:@selector(floatProperty)]; ```