2013-03-09 1 views
5

Questo è un estratto da Objective-C runtime programming guide:intesa Objective-C runtime

Quando viene creato un nuovo oggetto, memoria per essa è allocata, e le sue variabili di istanza vengono inizializzate. Il primo tra le variabili dell'oggetto è un puntatore alla sua struttura di classe. Questo puntatore, chiamato isa, fornisce all'oggetto l'accesso alla sua classe e, attraverso la classe, a tutte le classi da cui eredita.

isa è dichiarata in NSObject come questo:

Class isa; 

A sua volta Class è niente di più che un puntatore alla struct

typedef struct objc_class *Class; 

E ora diamo un'occhiata a questa struttura:

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 

} 

Possiamo vedere che il puntatore alla super classe (così come tutti gli altri membri della struct eccetto un altro isa) non è disponibile nell'ultima versione di Objective-C.

Quindi la mia domanda è come un oggetto può accedere alla sua superclasse se il puntatore super_class non è disponibile? Ha accesso alla superclasse attraverso questo un altro puntatore isa? Ma come succede esattamente? Come funziona? Qualcuno può spiegarlo?

+0

Dove hai trovato quella definizione? Questo file di intestazione ne mostra uno diverso: http://www.opensource.apple.com/source/objc4/objc4-208/runtime/objc-class.h – trojanfoe

+0

l'ho trovato in objc/runtime.h –

+0

dipende dal versione di runtime penso che –

risposta

7

appena controllato il file di origine

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; 
} 

così Class è in realtà un puntatore a 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; 

e questa è la struct che tiene tutto

in ogni caso, questi sono dettagli di implementazione interne e non devono essere considerate sopra. quindi non scrivere il codice che si basa su questi perché potrebbero non funzionare sul prossimo aggiornamento di runtime

+0

+1 Quasi il post la stessa cosa! – trojanfoe

+0

ehi, ma perché quando clicco salta su Definizione su Class ottengo qui typedef struct objc_class * Class ;? –

+1

@AndreyChernukha Immagino che sia lì per dare al compilatore qualcosa da guardare che nasconde i reali dettagli di implementazione. – trojanfoe

1

non fare affidamento su alcun interno della struttura di classe. - non ti affidi nemmeno ad altre variabili di istanza di amici! si guarda per le proprietà

tutto si può fare in tutta sicurezza con il runtime è in runtime.h

per ottenere l'egcall superclasse class_getSuperclass

+0

@downvoter: come sempre - perché? il consiglio è il suono –

+0

+1 su questa risposta per un buon consiglio. –