【发布时间】:2012-04-25 10:43:23
【问题描述】:
我尝试将我的一些 Objective-C 项目从 GCC 切换到 Linux 上的 Clang。
我使用了 GCC 4.6.2 运行时,因为 Clang 编译器没有附带一个。
编译和链接工作,但使用 protocol_* 方法时它们不起作用。
以下示例适用于 GCC,但不适用于 Clang:
#include <objc/runtime.h>
#include <stdio.h>
@protocol MyProtocol
+ aClassMethod;
- anInstanceMethod;
@end
void doIt(Protocol *p, SEL sel)
{
printf("the protocol: %p\n", p);
if (!p) return;
printf("the protocol's name: %s\n", protocol_getName(p));
struct objc_method_description d = protocol_getMethodDescription(p, sel, YES, YES);
printf("required: YES instance: YES → %p\n", d.name);
d = protocol_getMethodDescription(p, sel, YES, NO);
printf("required: YES instance: NO → %p\n", d.name);
d = protocol_getMethodDescription(p, sel, NO, YES);
printf("required: NO instance: YES → %p\n", d.name);
d = protocol_getMethodDescription(p, sel, NO, NO);
printf("required: NO instance: NO → %p\n", d.name);
}
int main(int argc, char **argv)
{
Protocol *p1 = @protocol(MyProtocol);
printf("P1\n");
printf("class method first:\n");
doIt(p1, @selector(aClassMethod));
printf("instance method follows:\n");
doIt(p1, @selector(anInstanceMethod));
Protocol *p2 = objc_getProtocol("MyProtocol");
printf("P2\n");
printf("class method first:\n");
doIt(p2, @selector(aClassMethod));
printf("instance method follows:\n");
doIt(p2, @selector(anInstanceMethod));
printf("done\n");
return 0;
}
GCC编译程序的预期输出:
P1
class method first:
the protocol: 0x804a06c
the protocol's name: MyProtocol
required: YES instance: YES → (nil)
required: YES instance: NO → 0x804b530
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
instance method follows:
the protocol: 0x804a06c
the protocol's name: MyProtocol
required: YES instance: YES → 0x804b528
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
P2
class method first:
the protocol: 0x804a06c
the protocol's name: MyProtocol
required: YES instance: YES → (nil)
required: YES instance: NO → 0x804b530
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
instance method follows:
the protocol: 0x804a06c
the protocol's name: MyProtocol
required: YES instance: YES → 0x804b528
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
done
Clang 编译程序的意外输出:
P1
class method first:
the protocol: 0x804a050
the protocol's name: (null)
required: YES instance: YES → (nil)
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
instance method follows:
the protocol: 0x804a050
the protocol's name: (null)
required: YES instance: YES → (nil)
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
P2
class method first:
the protocol: (nil)
instance method follows:
the protocol: (nil)
done
这里有什么问题? 是否有一些神奇的初始化代码在使用 Clang 时不会被调用?
[更新]
当添加如下协议的实现时,objc_getProtocol() 方法有效,但 protocol_* 方法仍然无效。
@interface MyInstance <MyProtocol>
@end
@implementation MyInstance
+ aClassMethod
{
return nil;
}
- anInstanceMethod
{
return nil;
}
@end
【问题讨论】:
-
如果您的图片中包含物理上采用协议的对象
@implementation,是否会导出协议信息?还是结果相同?例如:添加@interface MONObject : SOMEType < MyProtocol > @end \n @implementation MONObject \n @end然后重新运行。 -
protocol_*方法仍然不适用于协议的显式实现,但objc_getProtocol方法可以。 -
我尝试了您提到的 Apple 运行时 493.9 版本中的 protocol.m 测试。即使它是 GCC 运行时,我使用的测试在使用 GCC 编译时几乎通过了(
protocol_getMethodDescription()不提供与@selector()相同的指针,class_copyPropertyList()不起作用)。但是在使用 Clang 编译时它完全失败了(由于protocol_getName()返回NULL)。 -
@TiloPrütz 嗯。好奇的。我没有在 Linux 上安装正确的 objc 配置来测试它。
标签: objective-c clang objective-c-runtime