如何在运行时识别协议方法是可选的?

时间:2012-12-26 17:25:17

标签: objective-c ios cocoa ios5 protocols

我定义了我的协议。我已经提到我的两个协议方法是可选的。在运行期间,如何确定特定方法是否可选?有没有办法找出答案?

2 个答案:

答案 0 :(得分:12)

这应该做你想做的事:

BOOL MethodInProtocolIsRequired(Protocol *protocol, SEL methodSelector)
{
    struct objc_method_description methodDesc = protocol_getMethodDescription(protocol, methodSelector, YES, YES);
    return methodDesc.name != NULL;
}

请注意,我没有评论在运输代码中使用它的可行性,特别是因为您没有解释为什么要这样做。另请注意,当为协议不包含的方法指定选择器时,此函数将返回NO。这基本上是合理的(毕竟,如果一个协议不包含一个方法,它不是必需的!),但你可以通过检查协议是否包含该方法作为一个可选方法并返回不同的东西来为该函数添加复杂性。所有三种情况(必需,可选,非协议)。

编辑:这里简单的测试程序:https://gist.github.com/4381753

答案 1 :(得分:3)

(我不知道我头顶的答案.1分钟的谷歌搜索帮助了我。)

您可以使用protocol_copyMethodDescriptionList()函数执行此操作,该函数是Objective-C运行时库(libobjc)的一部分。此函数的第二个参数是一个布尔标志,指示是否需要在协议中复制的方法。因此,如果一个方法在这个函数返回的列表中(使用适当的参数调用),那么它就是一个必需的方法。

SEL sctr = @selector(isThisMethod:requiredIn:theProtocol:);

struct objc_method_description *methods;
unsigned int nMethods;
methods = protocol_copyMethodDescriptionList(
    objc_getProtocol("MyProtocolName"), // or @protocol(MyProtocolName) if you don't need this kind of dynamism
    YES, // required?
    YES, // instance method? (in general, protocols declare instance methods)
    &nMethods
);

BOOL isRequired = NO;
int i;
SEL s;
const char *sctrStr = sel_getName(sctr);
for (i = 0; i < nMethods; i++) {
    s = methods[i].name;
    const char *sStr = sel_getName(s);
    if (strcmp(sctrScr, sStr) == 0) {
        isRequired = YES;
        break;
    }
}

free(methods);

if (isRequired) {
    // required
} else {
    // optional
}

所以,这是可能的,但这有点过分,正如我在你对你的问题的评论中已经提到的,你不应该测试一个可选或必需的方法,你应该测试一个响应一个的实例特别选择器。

编辑:是的,而不是复制整个宇宙,我应该阅读文档中的内容。正如Andrew Madsen指出的那样,这可以简化为几行:

struct objc_method_description method;
method = protocol_getMethodDescription(
    objc_getProtocol("MyProtocolName"), // or @protocol(MyProtocolName)
    @selector(isThisSelector:required:)
    YES, // required?
    YES // instance method?
);

if (method.name != NULL) {
    // required
} else {
    // optional
}