【问题标题】:Understanding Objective-C runtime了解 Objective-C 运行时
【发布时间】:2013-03-09 10:07:59
【问题描述】:

这是Objective-C runtime programming guide的摘录:

当一个新对象被创建时,它的内存被分配,它的实例变量被初始化。对象变量中的第一个是指向其类结构的指针。这个称为 isa 的指针使对象可以访问其类,并通过该类访问它所继承的所有类。

isa 在NSObject 中声明如下:

Class   isa;

Class 只不过是一个指向结构的指针

typedef struct objc_class *Class;

现在让我们看看这个结构:

struct objc_class {
Class isa;

#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

}

我们可以看到,在最新版本的 Objective-C 中,指向超类(以及结构的所有其他成员,除了另一个 isa)的指针是不可用的。

所以我的问题是,如果super_class 指针不可用,对象如何访问其超类?它是否可以通过另一个 isa 指针访问超类?但它究竟是如何发生的?这个怎么运作?谁能解释一下?

【问题讨论】:

标签: objective-c objective-c-runtime


【解决方案1】:

刚刚检查了源文件

objc-class.m

Class class_getSuperclass(Class cls)
{
    return _class_getSuperclass(cls);
}

runtime-new.mm

#define newcls(cls) ((class_t *)cls)

Class 
_class_getSuperclass(Class cls)
{
    return (Class)getSuperclass(newcls(cls));
}

static class_t *
getSuperclass(class_t *cls)
{
    if (!cls) return NULL;
    return cls->superclass;
}

所以Class实际上是一个指向class_t的指针

objc-runtime-new.h

typedef struct class_t {
    struct class_t *isa;
    struct class_t *superclass;
    Cache cache;
    IMP *vtable;
    uintptr_t data_NEVER_USE;  // class_rw_t * plus custom rr/alloc flags

    class_rw_t *data() const { 
        return (class_rw_t *)(data_NEVER_USE & ~(uintptr_t)3); 
    }
    void setData(class_rw_t *newData) {
        uintptr_t flags = (uintptr_t)data_NEVER_USE & (uintptr_t)3;
        data_NEVER_USE = (uintptr_t)newData | flags;
    }

    bool hasCustomRR() const {
#if CLASS_FAST_FLAGS_VIA_RW_DATA
        return data_NEVER_USE & (uintptr_t)1;
#else
        return data()->flags & RW_HAS_CUSTOM_RR;
#endif
    }
    void setHasCustomRR(bool inherited = false);

    bool hasCustomAWZ() const {
#if CLASS_FAST_FLAGS_VIA_RW_DATA
        return data_NEVER_USE & (uintptr_t)2;
#else
        return data()->flags & RW_HAS_CUSTOM_AWZ;
#endif
    }
    void setHasCustomAWZ(bool inherited = false);

    bool isRootClass() const {
        return superclass == NULL;
    }
    bool isRootMetaclass() const {
        return isa == this;
    }
} class_t;

这是包含所有内容的结构

无论如何,这些都是内部实现细节,不应依赖。所以不要编写依赖这些的代码,因为它们可能会在下一次运行时更新时损坏

【讨论】:

  • 嘿,但是为什么当我单击跳转到类上的定义时,我会到这里 typedef struct objc_class *Class;?
  • @AndreyChernukha 我想它可以让编译器看到隐藏实际实现细节的东西。
  • 我注意到关于 objc4 项目的一件有趣的事情是 Visual Studio 项目文件以及 Xcode 项目文件。
  • 这些是实现细节,所以你看不到它们。并且因为Class是指针类型,所以它可以指向任何东西,只要代码使用指针知道指针实际指向的是什么。
  • 我是否理解没有办法通过 Xcode 找到 class_t 定义?
【解决方案2】:

不要依赖类结构的任何内部结构。 -- 你也不依赖其他 pals 实例变量!你寻找属性

您可以安全地使用运行时做的所有事情都在 runtime.h

用于获取超类,例如调用class_getSuperclass

【讨论】:

    猜你喜欢
    • 2010-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-26
    • 1970-01-01
    相关资源
    最近更新 更多