如何安全地测试是否可以通过NSInvocation调用方法

时间:2015-05-31 06:45:52

标签: swift cocoa objective-c-runtime scripting-bridge

我使用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

这让我觉得这是因为同样的原因。所以我不介意在自定义网桥中放弃对这些方法的支持。

2 个答案:

答案 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) {

}