Introspect参数类型:id来决定它是类还是协议

时间:2011-09-21 13:12:56

标签: objective-c protocols introspection

我有以下方法:

-(void)SomeMethod:(id)classOrProtocol;

它会像这样调用:

[self someMethod:@protocol(SomeProtocol)];

或者

[self someMethod:[SomeClass class]];

在方法体中,我需要决定是否| classOrProtocol |是:

任何类别(类别)或任何协议(协议)或其他任何内容

[[classOrProtocol class] isKindOfClass: [Protocol class]]

导致(构建)错误:

  

接收方'协议'是一个前向类,相应的@interface可能不存在

那么如何从一个类中告诉一个协议呢?

2 个答案:

答案 0 :(得分:2)

在Objective-C 2中(即除非您在OS X上使用32位运行时)Protocol被定义为只是前向类,请参阅/usr/include/objc/runtime.h。真实的界面没有声明。您可以尝试通过说

来包含/usr/inlcude/objc/Protocol.h
#import <objc/Protocol.h>

但正如在那里所写,Protocol的实例没有公开支持任何方法。处理Protocol实例的唯一可接受的方法是使用Objective-C Runtime Reference中给出的运行时函数。它甚至没有公开定义Protocol是否是任何事物的子类,甚至没有声明它实现NSObject协议。所以你不能在它上面调用任何方法。

当然,您可以使用运行时的源代码来查看正在发生的事情。 Protocol继承自Object(来自OpenStep之前的NeXTSTep的残余),而非NSObject。因此,您无法使用熟悉的NSObject派生对象方法,包括ClassNSObject派生对象。请参阅Protocol.hProtocol.m的开源实现。正如您所看到的,类Protocol本身不会执行任何操作,因为每个方法只会将self强制转换为protocol_t并调用函数。实际上,从函数_read_imagesobjc-runtime-new.mm中的其他函数可以看出,isa对象的Protocol指针是手动设置 加载可执行文件和库时,从未使用过。

因此,请勿尝试检查id是否为Protocol

如果您确实需要这样做,可以使用

id foo=...;
if(foo->isa==class_getClass("Protocol")){
    ...
}

但是,严肃地说,不要这样做。

答案 1 :(得分:-1)

这不是由于无法确定它的类或协议而导致的问题。该错误是由Protocol类的缺少接口引起的。确保在实验文件的顶部导入Protocol.m,您正在测试参数的类型。

您还可以尝试使用NSClassFromString()函数,该函数将返回Class个对象或nil。请注意,如果返回nil,则并不意味着参数是协议。它只是意味着它也可能是未定义的类!

还有方法NSProtocolFromString返回适当的结果 - 协议协议和未定义协议的nil