【问题标题】:Why do protocol_* methods do not work with Clang + modern GCC-Runtime on Linux?为什么 protocol_* 方法不适用于 Linux 上的 Clang + 现代 GCC-Runtime?
【发布时间】: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 &lt; MyProtocol &gt; @end \n @implementation MONObject \n @end 然后重新运行。
  • protocol_* 方法仍然不适用于协议的显式实现,但 objc_getProtocol 方法可以。
  • 如果编译并运行this test会发生什么(别忘了header?如果它失败了,那么在实现中存在潜在的错误。
  • 我尝试了您提到的 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


【解决方案1】:

在我的测试中,GCC 与它包含的 GNU libobjc 配合得很好,但 Clang 与 GNUstep libobjc2 配合得更好。

GCC 4.6 w/包括 GNU libobjc:通过

P1 类方法优先: 协议:0x602120 协议名称:MyProtocol 必需:YES 实例:YES → (nil) 必需:YES 实例:NO → 0x10eda50 必需:否实例:是→(无) 必需:NO 实例:NO → (nil) 实例方法如下: 协议:0x602120 协议名称:MyProtocol 必需:YES 实例:YES → 0x10eda40 必需:是实例:否→(无) 必需:否实例:是→(无) 必需:NO 实例:NO → (nil) P2 类方法优先: 协议:0x602120 协议名称:MyProtocol 必需:YES 实例:YES → (nil) 必需:YES 实例:NO → 0x10eda50 必需:否实例:是→(无) 必需:NO 实例:NO → (nil) 实例方法如下: 协议:0x602120 协议名称:MyProtocol 必需:YES 实例:YES → 0x10eda40 必需:是实例:否→(无) 必需:否实例:是→(无) 必需:NO 实例:NO → (nil) 完毕

GCC 4.6 w/libobjc2 1.6:失败

P1 类方法优先: 协议:0x602120 协议名称:MyProtocol 必需:YES 实例:YES → (nil) 必需:YES 实例:NO → 0x6020a0 必需:否实例:是→(无) 必需:NO 实例:NO → (nil) 实例方法如下: 协议:0x602120 协议名称:MyProtocol 必需:YES 实例:YES → 0x6020b0 必需:是实例:否→(无) 必需:否实例:是→(无) 必需:NO 实例:NO → (nil) P2 类方法优先: 协议:(无) 实例方法如下: 协议:(无) 完毕

带有 GCC 4.6 GNU libobjc 的 Clang 3.1:失败

P1 类方法优先: 协议:0x602080 协议名称:(空) 必需:YES 实例:YES → (nil) 必需:是实例:否→(无) 必需:否实例:是→(无) 必需:NO 实例:NO → (nil) 实例方法如下: 协议:0x602080 协议名称:(空) 必需:YES 实例:YES → (nil) 必需:是实例:否→(无) 必需:否实例:是→(无) 必需:NO 实例:NO → (nil) P2 类方法优先: 协议:(无) 实例方法如下: 协议:(无) 完毕

带有 libobjc2 1.6 的 Clang 3.1:通过

P1 类方法优先: 协议:0x602080 协议名称:MyProtocol 必需:YES 实例:YES → (nil) 必需:是实例:否→(无) 必需:否实例:是→(无) 必需:NO 实例:NO → (nil) 实例方法如下: 协议:0x602080 协议名称:MyProtocol 必需:YES 实例:YES → (nil) 必需:是实例:否→(无) 必需:否实例:是→(无) 必需:NO 实例:NO → (nil) P2 类方法优先: 协议:0x602080 协议名称:MyProtocol 必需:YES 实例:YES → (nil) 必需:是实例:否→(无) 必需:否实例:是→(无) 必需:NO 实例:NO → (nil) 实例方法如下: 协议:0x602080 协议名称:MyProtocol 必需:YES 实例:YES → (nil) 必需:是实例:否→(无) 必需:否实例:是→(无) 必需:NO 实例:NO → (nil) 完毕

【讨论】:

  • 从技术上讲,这个问题仍然没有答案。我接受了您的回答,因为它可以解决我的问题。坦克。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-21
  • 1970-01-01
  • 2022-11-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多