6

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

4

2 回答 2

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

于 2012-12-26T17:41:05.310 回答
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
}
于 2012-12-26T17:40:11.990 回答