我使用ObjC运行时生成了一个类的方法和属性列表,以便稍后可以使用NSInvocation从桥中调用它们。
问题是,对于那些运行时无法生成签名的方法,我遇到了错误。
例如,在direction
的实例中调用SKFieldNode
的属性getter抛出异常NSInvalidArgumentException
,我猜这是因为vector_float3
没有编码类型, type是''(即没有字符类型)
这是测试我所描述的内容的方法:
Method method = class_getInstanceMethod([SKFieldNode class], @selector(direction));
const char *types = method_getTypeEncoding(method);
NSMethodSignature *sig = [NSMethodSignature signatureWithObjCTypes:types];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:sig];
SKFieldNode *field = [SKFieldNode node];
field.direction = (vector_float3){1,2,3};
[inv setTarget:field];
[inv setSelector:@selector(direction)]; // (*)
[inv invoke];
vector_float3 v;
[inv getReturnValue:&v];
NSLog(@"%f %f %f", v.x, v.y, v.z);
(*)“NSInvalidArgumentException”,“ - [NSInvocation setArgument:atIndex:]:index(1)out of bounds [-1,0]“
如何使用内省来判断是否可以通过这种方式安全地调用方法?
我尝试测试NSMethodSignature
返回的参数数量,但是对于缺少编码类型的方法,该值是错误的,例如,这两个方法将返回2,计算目标和选择器,以便剩下的不考虑参数。
- setDirection:(vector_float3)d1 direction:(vector_float3)d2;
- setDirection:(vector_float3)d;
我也注意到了方向属性is not available in Swift
这让我觉得这是因为同样的原因。所以我不介意在自定义网桥中放弃对这些方法的支持。
答案 0 :(得分:1)
这是一个相当简单的检查,以确保您没有任何不正确编码的参数:
BOOL isMethodSignatureValidForSelector(NSMethodSignature *signature, SEL selector) {
// This could break if you use a unicode selector name, so please don't do that :)
const char *c_str = sel_getName(selector);
unsigned numberOfArgs = 2;
while (*c_str) {
if (*c_str == ':') {
numberOfArgs++;
};
c_str++;
}
return ([signature numberOfArguments] == numberOfArgs);
}
答案 1 :(得分:0)
您可以使用try-catch
语句尝试运行一些代码:
@try {
Method method = class_getInstanceMethod([SKFieldNode class], @selector(direction));
const char *types = method_getTypeEncoding(method);
NSMethodSignature *sig = [NSMethodSignature signatureWithObjCTypes:types];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:sig];
SKFieldNode *field = [SKFieldNode node];
field.direction = (vector_float3){1,2,3};
[inv setTarget:field];
[inv setSelector:@selector(direction)]; // (*)
[inv invoke];
vector_float3 v;
[inv getReturnValue:&v];
NSLog(@"%f %f %f", v.x, v.y, v.z);
} @catch (NSException *exception) {
}