Jul*_*era 5 reflection casting objective-c performselector
对 performSelector 的结果进行 float / double / CGFloat 转换会发生一种非常奇怪的行为:
为什么这样做?
BOOL property = (BOOL)[self.object performSelector:@selector(boolProperty)];
NSInteger property = (NSInteger) [self.object performSelector:@selector(integerProperty)];
Run Code Online (Sandbox Code Playgroud)
而这并没有
CGFloat property = (CGFloat) [self.object performSelector:@selector(floatProperty)];
Run Code Online (Sandbox Code Playgroud)
起初我试图这样做:
CGFloat property = [[self.object performSelector:@selector(floatProperty)] floatValue];
Run Code Online (Sandbox Code Playgroud)
但我最终收到了 EXC_BAD_ACCESS 运行时错误。我已经想出了解决这个问题的方法,但我想了解为什么它适用于 Integer 和 Bool 而不是浮点类型。
我的黑客:
@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
Run Code Online (Sandbox Code Playgroud)
然后:
CGFloat property = [self.object performFloatSelector:@selector(floatProperty)];
Run Code Online (Sandbox Code Playgroud)
该performSelector方法仅支持不返回任何内容或对象的方法。这在其文档中进行了说明,其中指出:
对于返回对象以外的任何内容的方法,请使用
NSInvocation.
您的“hack”只是调用返回非对象的选择器的正确方法。
它似乎适用于整数和布尔方法的原因与方法返回值的方式有关。的返回类型performSelector是id,一个对象指针类型。类整数值;其中包括NSInteger,BOOL和 对象指针;通常在通用寄存器中返回,但是浮点值通常在浮点寄存器中返回。编译器将始终从用于返回id值的寄存器加载结果,然后执行转换所需的任何操作。对于整数和布尔值,加载的值可能是正确的,并且在这些情况下强制转换是无操作的,因此一切(似乎)都可以工作。对于浮点值,加载的值不正确 - 它不是被调用方法返回的值,因为它在不同的寄存器中。
请注意,performSelector在 ARC 下调用非对象、非空的选择器可能会导致内存问题——如果是这种情况,编译器通常会发出警告。
NSInvocation调用选择器的方式适用于非对象返回类型,因为它的参数之一是方法签名本身。使用签名NSInvocation能够确定返回值的类型及其返回方式,从而正确地将其返回给调用者。
HTH