iOS / Objective-C - struct objc_class *和struct objc_object *

时间:2014-01-01 23:42:34

标签: ios objective-c struct objective-c-runtime

我的理解是 Objective-C 中的对象只是结构

分别只是:

struct objc_class *

struct objc_object *

问题#1:

objc_msgSend(id self, SEL _cmd);
据我所知,

id的类型为struct objc_object *

但是当我们调用类方法时,类是struct objc_class *

我希望它会引起问题或者喊出某种警告,例如“嘿,这里的错误类型,我的朋友”。

但没有。

  • 为什么?

这只是为了满足我的好奇心,因为即使没有完全理解这一点,它似乎也没有给我带来任何麻烦(到目前为止)。但我想深入挖掘并学习基本原理/“特点”。

问题#2:

由于根据我的经验(与 问题#1 相关)没有警告,因此我不太确定他们可能< / em>可以互换使用。

struct objc_class *struct objc_object * 真的可以互换使用吗?

如果是:

  • 您能否向我展示一个场景和样本,以及/如何/为何需要互换使用这些场景?

  • 利益(如果有),缺点(如果有)和“陷阱”(需要注意的事项)出去;如果有的话)这样做?

2 个答案:

答案 0 :(得分:8)

  

我的理解是Objective-C中的对象和类只是结构。

这不是真的,特别是因为ObjC2,并且绝对不是一个好的思考方式。有问题的“结构”定义了一个字段(isa)。而已。它只是名义上的“结构”。

请注意,ARC对象和结构在编译器中的处理方式不同。对象指针将获得结构指针不会的特殊处理(包括nil-initialization)。编译器还将->不同地应用于对象而不是结构。结构指针必须具有在->之后给出名称的字段。 objc_object只有一个字段(isa)。由于可以在运行时定义和重新定义类层次结构,因此编译器无法像编译结构那样在编译时为对象评估->

我提出这一点是因为在C ++中,对象和结构只是同一个东西的略有不同的版本,你可以轻松地在它们之间进行交换。你不能在ObjC中安全地做到这一点。它们几乎不相似。

  

但是当我们调用类方法,类struct objc_class *的类时,我希望它会导致问题......

This is because classes are objects.对象未定义为objc_object类型。它们是根据isa字段(它曾经是指针,但现在可能是指针,or it might not)来定义的。这是假设typedef是重要的问题的一部分。事实并非如此。重要的是它是否像一个物体。 Objective-C是一种主要是鸭式的语言。如果它像一个对象,它就是一个对象。

BTW,NSProxy也生活在这个奇怪的近乎对象的世界里。如果你注意它的定义,它不会从任何东西继承,但它确实声明了isa字段作为它的第一个ivar。这是让它像对象一样行动的关键部分。

  

结构objc_class *和struct objc_object *真的可以互换使用吗?

没有。您通常可以将类传递给任何想要对象的东西(因为类是对象),但是您不能将对象传递给想要类的东西。

答案 1 :(得分:5)

我在runtime.h文件中找到它。

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;


struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

objc_class和objc_object都有isa变量,objc_object中的isa指向描述实例并存储实例方法列表的Class。 objc_class中的Isa也指向Class,但它是描述类并存储类方法列表的元类。

The link对您有用。

我已经模拟了病情。

struct A {
    int a ;
} ;

typedef struct A *PA ;

struct B {
    int a ;
    int b ;
} ;

void dosomething(PA pa)
{
    printf("%d", (*pa).a) ;
}

+ (void)hei
{
    struct B b ;
    b.a = 10 ;
    b.b = 20 ;
    // without forced cast, i will get a warning but work well
    dosomething((PA)&b) ;
}

您可以使用struct B *代替struct A *,因为编译器和链接器会将int a放在相同的相对地址中。

为什么编译器在调用将struct objc_class *传递给objc_msgSend(id self, SEL _cmd);的类方法时不会抱怨,在我看来编译器会考虑它。