Isa analyzes to metaclass

  • We know thatClassobjc_class*A type is just a pointer,objc_classIs the inheritance andobjc_object, soClassThere is aisathe
typedef struct objc_class *Class;

/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

struct objc_class: objc_object {
  // isa. } Class isaCopy the code

LLDB analysis isa

  • Pass objectisaYou can get classes, that kind of thingisaAnd what is it that is deposited so that it may pass throughlldbPrint to see the results

  • As you can see from the print above, isa(–>) object –> class –> metaclass –> root metaclass –> root metaclass
  • Of the classisaSo what I’m going to store isThe metaclassYou don’t need to passmaskMask to get, only the object isnonpointer. Because only objects have reference counts, weak references, etc
  • It also follows that the class is also an object, which implies that everything is connected to objects

teacherIs inheritedperson, check through the LLDBtachertheisa

  • We can drawteachertheThe metaclassAlso points toA metaclass

Inheritance of relation to ISA

  • ->saidinheritance metasaidThe metaclass
  • WLWTeacher -> WLWPerson -> NSObject -> nil
  • WLWTeacher(meta) -> WLWPerson(meta) -> NSObject(meta) -> NSobject -> nil
  • The metaclassThere is ainheritanceWill inherit the parent metaclass, all the way to the root metaclass
  • The inherited root class of the root metaclass

Isa and inheritance of NSProxy

  • NSProxyIs to comply withNSObjectThe protocol is also the root class, so it’s the same as the NSOject root class, just the root classNSProxy
  • soNSProxywithNSObjecIt’s sibling, it’s root

The code to print

    // NSObject instance object
    NSObject *object1 = [NSObject alloc];
    / / NSObject class
    Class class = object_getClass(object1);
    // NSObjectThe metaclassClass metaClass = object_getClass(class);
    // NSObjectA metaclassClass rootMetaClass = object_getClass(metaClass);
    // NSObjectSpikes metaclassClass rootRootMetaClass = object_getClass(rootMetaClass);
    NSLog(@ \"n%pInstance object \n%pClass \n%pThe metaclass \n%pA metaclass \n%pRoot metaclass ",object1.class.metaClass.rootMetaClass.rootRootMetaClass);
    
    // LGPersonThe metaclassClass pMetaClass = object_getClass(LGPerson.class);
    Class psuperClass = class_getSuperclass(pMetaClass);
    NSLog(@ "% @ - %p",psuperClass.psuperClass);
    
    // LGTeacher -> LGPerson -> NSObject// The metaclass also has an inheritance chainClass tMetaClass = object_getClass(LGTeacher.class);
    Class tsuperClass = class_getSuperclass(tMetaClass);
    NSLog(@ "% @ - %p",tsuperClass.tsuperClass);
    
    // NSObjectRoot class special caseClass nsuperClass = class_getSuperclass(NSObject.class);
    NSLog(@ "% @ - %p",nsuperClass.nsuperClass); // root metaclass ->NSObject
    Class rnsuperClass = class_getSuperclass(metaClass);
    NSLog(@ "% @ - %p",rnsuperClass.rnsuperClass);
Copy the code

Apple’s official

conclusion

  • Everything is an object, the class has only one address, so the system creates a singleton object for you, and then we create the object based on the new memory that the class inherits
  • The metaclassThere are also inheritance relationships,The metaclassinheritanceThe metaclass of the parent class
  • A metaclassinheritanceThe root class, root class inheritancenil
  • Object ISA -> class ISA -> metaclass ISA -> root metaclass ISA -> root metaclass
  • Root class ISA -> root metaclass ISA

The structure of the source analysis class

struct objc_class : objc_object {
  objc_class(const objc_class&) = delete;
  objc_class(objc_class&&) = delete;
  void operator= (const objc_class&) = delete;
  void operator=(objc_class&&) = delete;
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags. . }Copy the code
  • Since there are many methods in the class structure, we first analyze the member variables in the class structure
  • There are four member variables in this class,

Class ISA

  • The first one is hiddenClass ISATo inherit fromobjc_objectAnd we know where it leadsThe metaclassTheta is a pointer, so theta8 bytes

superClass

  • The secondsuperClassIt’s obviously pointing to the parent class, which is also a pointer8 bytes

cache_t cache

  • The thirdcache_t cacheThis is a very important one. It’s well understood that it’s a cache. What does it cache
    • Look at thecache_tThe structure of the body
    struct cache_t {
    private:
    // explicit_atomic
            
              define type to allow conversion, uintptr_t = unsigned long
            
    explicit_atomic<uintptr_t>  _bucketsAndMaybeMask; / / 8 bytes
    // Member variables are mutually exclusive
    union {
        struct {
            // mask_t: mac: uint32_t 
            / / mask
            explicit_atomic<mask_t>    _maybeMask; / / 4 bytes
         #if __LP64__
            / / tag
            uint16_t                   _flags; / / 2 bytes
         #endif
            // Occupied number
            uint16_t                   _occupied; / / 2 bytes
        };
        // Pointer, raw rule cache
        explicit_atomic<preopt_cache_t *> _originalPreoptCache; / / 8 bytes
    };
    Copy the code
    • You can work outcache_tThe size is16byte

class_data_bits_t

  • The fourthclass_data_bits_t bitsI put some data in it and according to the notes, yesclass_rw_t *addrr/allocThe custom offlags, the source code can also be used with the look rough8 bytes
Struct class_data_bits_t {// friend friend objc_class; // Values are the FAST_ flags above. uintptr_t bits; // 8 bytes... .Copy the code

LLDB analyzes the structure of the class

  • According to thecache_tThe internal structure of the0x000000019a7033e0is_bucketsAndMaybeMask.0x0000801900000000It’s the union
  • class_data_bits_tThat’s the inside of itbits

Class bits data analysis

  • Do we know how to find itbits, we print it out in the source environment
  • Not in a non-source environmentclass_data_bits_tType. You cannot print its structure, but you can print it by copying the underlying code

class_rw_t *data(a) const {
    return bits.data();
}
Copy the code
  • throughlldbPrint out the memory address and pass throughobjc_classWe have access to the methods provided by$46 = class_rw_t
  • firstSubClassIs assigned at run time
  • You can see that the class is a tree

Class_rw_t (dirty Memory)

struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags; / / tag
uint16_t witness; // 
#if SUPPORT_INDEXED_ISA
uint16_t index;
#endif

explicit_atomic<uintptr_t> ro_or_rw_ext;

Class firstSubclass; / / subclass
Class nextSiblingClass; / / brother
Copy the code
class_rw_tThe falgs tag// Values for class_rw_t->flags
// These are not emitted by the compiler and are never used in class_ro_t.
// Their presence should be considered in future ABI versions.
// class_t->data is class_rw_t, not class_ro_t
#define RW_REALIZED           (1<<31)
// class is unresolved future class
#define RW_FUTURE             (1<<30)
// class is initialized
#define RW_INITIALIZED        (1<<29)
// class is initializing
#define RW_INITIALIZING       (1<<28)
// class_rw_t->ro is heap copy of class_ro_t
#define RW_COPIED_RO          (1<<27)
// class allocated but not yet registered
#define RW_CONSTRUCTING       (1<<26)
// class allocated and registered
#define RW_CONSTRUCTED        (1<<25)
// available for use; was RW_FINALIZE_ON_MAIN_THREAD
// #define RW_24 (1<<24)
// class +load has been called
#define RW_LOADED             (1<<23)
#if! SUPPORT_NONPOINTER_ISA
// class instances may have associative references
#define RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS (1<<22)
#endif
// class has instance-specific GC layout
#define RW_HAS_INSTANCE_SPECIFIC_LAYOUT (1 << 21)
// class does not allow associated objects on its instances
#define RW_FORBIDS_ASSOCIATED_OBJECTS       (1<<20)
// class has started realizing but not yet completed it
#define RW_REALIZING          (1<<19)

#if CONFIG_USE_PREOPT_CACHES
// this class and its descendants can't have preopt caches with inlined sels
#define RW_NOPREOPT_SELS      (1<<2)
// this class and its descendants can't have preopt caches
#define RW_NOPREOPT_CACHE     (1<<1)
#endif

// class is a metaclass (copied from ro)
#define RW_META               RO_META / / (1 < < 0)
Copy the code
  • class_rw_tSome of the internal methods

// Get ro clean memory
const class_ro_t *ro(a) const {
    auto v = get_ro_or_rwe();
    if (slowpath(v.is<class_rw_ext_t* > ())) {return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro;
    }
    return v.get<const class_ro_t *>(&ro_or_rw_ext);
}

// Set ro clean memory
void set_ro(const class_ro_t *ro) {
    auto v = get_ro_or_rwe();
    if (v.is<class_rw_ext_t *>()) {
        v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro = ro;
    } else{ set_ro_or_rwe(ro); }}// Get method
const method_array_t methods(a) const {
    auto v = get_ro_or_rwe();
    if (v.is<class_rw_ext_t* > ()) {return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods;
    } else {
        return method_array_t{v.get<const class_ro_t*>(&ro_or_rw_ext)->baseMethods()}; }}// Get attributes
const property_array_t properties(a) const {
    auto v = get_ro_or_rwe();
    if (v.is<class_rw_ext_t* > ()) {return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties;
    } else {
        return property_array_t{v.get<const class_ro_t*>(&ro_or_rw_ext)->baseProperties}; }}// Get the protocol
const protocol_array_t protocols(a) const {
    auto v = get_ro_or_rwe();
    if (v.is<class_rw_ext_t* > ()) {return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->protocols;
    } else {
        return protocol_array_t{v.get<const class_ro_t*>(&ro_or_rw_ext)->baseProtocols}; }}Copy the code
properties()

  • Member variables don’t exist here, only propertiesproperty
methods()

  • Methods have properties generated in themset, getmethods
  • There is noClass methodThat’s what’s called+Number method, existence-No way to
  • types = 0x0000000100003df7 "v24@0:8@16", the firstvRepresents the return valuevoidBelow is the comparison table

protocols()

  • protocolsThe bottom isprotocol_tThe structure of the body
class_ro_t
ivars

  • The member variable existsclass_ro_ttheivarsIn,
  • And it also stores the underlined attributes generated_The variables of
baseProperties

  • ro basePropertiesAnd rwpropertiresThe same
baseMethodList

ro rw

  • You can see that the address is the same, and the way to store it is the same
baseProtocols

rw ro

  • The address is the same