为什么protocol_ *方法不适用于Linux上的Clang +现代GCC-Runtime?

时间:2012-04-25 10:43:24

标签: objective-c clang objective-c-runtime

我尝试将一些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

1 个答案:

答案 0 :(得分:2)

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

GCC 4.6 w /包含GNU libobjc:PASS

P1
class method first:
the protocol: 0x602120
the protocol's name: MyProtocol
required: YES instance: YES → (nil)
required: YES instance: NO → 0x10eda50
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
instance method follows:
the protocol: 0x602120
the protocol's name: MyProtocol
required: YES instance: YES → 0x10eda40
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
P2
class method first:
the protocol: 0x602120
the protocol's name: MyProtocol
required: YES instance: YES → (nil)
required: YES instance: NO → 0x10eda50
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
instance method follows:
the protocol: 0x602120
the protocol's name: MyProtocol
required: YES instance: YES → 0x10eda40
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
done

GCC 4.6 w / libobjc2 1.6:失败

P1
class method first:
the protocol: 0x602120
the protocol's name: MyProtocol
required: YES instance: YES → (nil)
required: YES instance: NO → 0x6020a0
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
instance method follows:
the protocol: 0x602120
the protocol's name: MyProtocol
required: YES instance: YES → 0x6020b0
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 3.1 w / GCC 4.6 GNU libobjc:FAIL

P1
class method first:
the protocol: 0x602080
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: 0x602080
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 3.1 w / libobjc2 1.6:PASS

P1
class method first:
the protocol: 0x602080
the protocol's name: MyProtocol
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: 0x602080
the protocol's name: MyProtocol
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: 0x602080
the protocol's name: MyProtocol
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: 0x602080
the protocol's name: MyProtocol
required: YES instance: YES → (nil)
required: YES instance: NO → (nil)
required: NO instance: YES → (nil)
required: NO instance: NO → (nil)
done