The analysis of the class

The isa of an object refers to a class. Everything is an object. The class is also an object. This class is the metaclass defined by Apple

metaClass

Existence is reasonable, where is the significance of the existence of metaclass?

int main(int argc, char * argv[]) {
    @autoreleasepool {
       Class class1 = [SWPerson class];
       Class class2 = [SWPerson alloc].class;
       Class class3 = object_getClass([SWPerson alloc]);
       Class class4 = [SWPerson alloc].class;
       NSLog(@"\n-%p-\n-%p-\n-%p-\n-%p-",class1,class2,class3,class4);
    }
    return} Result: -0x100009510-
-0x100009510-
-0x100009510-
-0x100009510-
Copy the code
  • The addresses of class objects are the same, and each class has only one piece of memory, which is obviously different from ordinary objects

Is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask = is_mask Define ISA_MASK 0x00007ffffffffff8ULL arm64: define ISA_MASK 0x0000000ffffffff8ULL arm64 (Simulators) : define ISA_MASK 0x007ffffffffffff8ULL

  1. P /x swPerson. class gets the memory address of the class object 0x00000001000080E8, and x/4gx formats the memory address of the class object
  2. P /x 0x00000001000080C0&0x00007ffffFFFFff8 set the first address of the class object (ISA pointer address)0x00000001000080c0 and ISA_MASK, We get a new memory address 0x00000001000080c0
  3. Po 0x00000001000080C0 prints the address data and gets SWPerson

0x00000001000080E8 and 0x00000001000080C0 are two different addresses. 0x00000001000080E8 is a class address, and the class corresponding to 0x00000001000080C0 is called a metaclass

summary

  • Metaclasses are created automatically by the system compiler, independent of the user
  • The ISA of an instance object points to a class, and the ISA of a class object points to a metaclass
  • The name of a class is the same as the name of its associated metaclass (only associated metaclass has a class name)

Isa bitmap analysis

Apple official ISA location and inheritance chart

  • Isa –> class object of instance object
  • Isa –> metaclass for class objects
  • Metaclass ISA –> root metaclass
  • Isa of the root metaclass –> root metaclass (pointing to itself)

Class metaclass root metaclass inheritance diagram

int main(int argc, char * argv[]) {
    @autoreleasepool {
    Class tMetaClass = object_getClass(SWTeacher.class);    / / SWTeacher metaclass
    Class tMetaSuperClass = class_getSuperclass(tMetaClass);// the parent of SWTeacher's metaclass
    
    Class pMetaClass = object_getClass(SWPerson.class);     / / SWPerson metaclass
    Class pMeatSuperClass = class_getSuperclass(pMetaClass);// The parent of SWPerson's metaclass
   
    Class nMetaClass = object_getClass(NSObject.class);     / / NSObject metaclass
    Class nSuperClass = class_getSuperclass(NSObject.class);/ / parent class NSObject
    Class nMetaSuperClass = class_getSuperclass(nMetaClass);// the parent of NSObject's metaclass
    
    NSLog(@"SWTeacher-%p",SWTeacher.class);
    NSLog(@"SWPerson-%p",SWPerson.class);
    NSLog(@"NSObject-%p",NSObject.class);
 
    NSLog(@"%@ - %p - %@ - %p",tMetaClass,tMetaClass,tMetaSuperClass,tMetaSuperClass);
    NSLog(@"%@ - %p - %@ - %p",pMetaClass,pMetaClass,pMeatSuperClass,pMeatSuperClass);
    NSLog(@"%@ - %p - %@ - %p",nMetaClass,nMetaClass,nMetaSuperClass,nMetaSuperClass);
    }
    return 
}

SWTeacher-0x100009618
SWPerson-0x100009528
NSObject-0x7fff8deb3118
SWTeacher - 0x1000095f0 - SWPerson - 0x100009500
SWPerson - 0x100009500 - NSObject - 0x7fff8deb30f0
NSObject - 0x7fff8deb30f0 - NSObject - 0x7fff8deb3118-- -- (null)

Copy the code

The parent class of NSObject prints nil. The parent of SWTeacher’s metaclass is the metaclass of SWPerson (the address of the metaclass of SWPerson is different from the address of the SWPerson class). The parent of the metaclass of SWPerson is the metaclass of NSObject, and the parent of the metaclass of NSObject is NSObject (same address as NSObject)

  • SWTeacherinheritanceSWPerson.SWPersoninheritanceNSObject.NSObjectIs the parent classnil
  • SWTeacherYuan class inheritanceSWPersonMetaclasses,SWPersoninheritanceA metaclass.A metaclassinheritanceNSObject

Class structure analysis

Isa is of Class type, Class is objc_class*, objc_class isa structure, all the underlying implementation of Class is objc_class

struct objc_class : objc_object {
     ...
    // 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

    // Here are some methods to omit};Copy the code

Objc_class inherits from objc_Object, which has only one member variable isa. We’ve already explored what isa does. The specific function of the following three member variables is unknown, how to explore it? The address of the class is known, so get the address of the inside member variable based on the first address + offset value explored above, and then get the value. But offset values need to know the sizes of all member variables before the current variable

  • isaThe structure pointer takes 8 bytes
  • Class superclassAlso, the structure pointer takes 8 bytes
  • cache_t cacheIs the size of the struct type, determined by the struct body member variable. 16 bytes
  • class_data_bits_t bitsKnowing the size of the first three member variables, we can get the address of the bits

Cache_t Memory size

typedef unsigned long           uintptr_t;

#if __LP64__
typedef uint32_t mask_t;  // x86_64 & arm64 asm are less efficient with 16-bits
#else
typedef uint16_t mask_t;
#endif

struct cache_t {
private:
    explicit_atomic<uintptr_t> _bucketsAndMaybeMask; / / 8
    union {
        struct {
            explicit_atomic<mask_t>    _maybeMask;   / / 4
#if __LP64__
            uint16_t                   _flags;       / / 2
#endif
            uint16_t                   _occupied;    / / 2
        };
        explicit_atomic<preopt_cache_t *> _originalPreoptCache; / / 8
    };
    
    // Here are some methods to omit
};
Copy the code

Cache_t is a structure type with two member variables _bucketsAndMaybeMask and a union

  • _bucketsAndMaybeMaskUintptr_t unbroken long integer type of 8 bytes
  • The union has two member variable structures and_originalPreoptCacheThe memory size of the union is determined by the maximum variable type in the member variable
  • _originalPreoptCacheThe structure pointer is 8 bytes
  • It’s in the structure_maybeMask._flags._occupied._maybeMaskUint32_t takes up 4 bytes,_flagsand_occupiedIs the Uint16_t each of 2 bytes, structure size is 8 bytes
  • cache_tThe memory size of 8+8 or 8+4+2+2 is 16 bytes

Summary: By fetching class_rw_t* data(), you get the methods, properties, protocols, deepCopy, ro, and so on for that class

class_rw_t

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

// Some code is omitted
    explicit_atomic<uintptr_t> ro_or_rw_ext;

    Class firstSubclass;
    Class nextSiblingClass;


    class_rw_ext_t *deepCopy(const class_ro_t *ro) {
        return extAlloc(ro, true);
    }

    const method_array_t methods() 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<constclass_ro_t *>(&ro_or_rw_ext)->baseMethods()}; }}const property_array_t properties() 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<constclass_ro_t *>(&ro_or_rw_ext)->baseProperties}; }}const protocol_array_t protocols() 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<constclass_ro_t *>(&ro_or_rw_ext)->baseProtocols}; }}};Copy the code

Attributes of a class

Member variable acquisition process: nsobject. class -> class_data_bits_t -> class_rw_T -> property_array_t -> property_list_t -> property_t

Class instance method

Nsobject. class -> class_data_bits_t -> class_rw_T -> method_array_t -> method_list_t -> method_t -> BIG

Member variables

Nsobject. class -> class_datA_bits_t -> class_rw_T -> class_ro_t -> ivar_list_t -> ivar_t

The underlying implementation of a variable isivar_t. Stored in theclass_ro_tThe system automatically generates a band for the property in the variable list_Property name variable, stored inclass_ro_tIn a list of variables

Class method

Class method acquisition process: NSObject.class -> metaClass -> class_data_bits_t -> class_rw_t -> method_array_t -> method_list_t -> method_t -> big

Conclusion: Class methods are stored inYuan classIn the list of methods

The source code

View the source code isObjc4-818.2. Tar. Gz