6

これはからの抜粋です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ポインタを介してスーパークラスにアクセスできますか?しかし、それはどのように正確に起こりますか?使い方?誰かがそれを説明できますか?

4

2 に答える 2

8

ソースファイルを確認しました

objc-class.m

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

ランタイム-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;

これはすべてを保持する構造体です

いずれにせよ、これらは内部実装の詳細であり、依存すべきではありません。これらに依存するコードを記述しないでください。次回のランタイム更新で壊れる可能性があるためです

于 2013-03-09T10:26:28.023 に答える
1

クラス構造体の内部に依存しないでください。-- 他の pals インスタンス変数にも依存しません! あなたはプロパティを探します

ランタイムで安全にできることはすべてruntime.h

スーパークラスの egcall を取得するためclass_getSuperclass

于 2013-03-09T10:20:04.103 に答える