Objc_object vs. objc_class

  1. objc_objectThe correspondingobject, it isobjectAt the bottomThe data structure.
  2. objc_classThe correspondingclass, it isclassAt the bottom of theThe data structure
  3. idforObjc_object pointertheThe alias
typedef struct objc_object *id; `Copy the code
  1. classforObjc_class pointertheThe alias
typedef struct objc_class *Class;
Copy the code
  1. objc_classInheritance inobjc_objectEverything is an object
struct objc_class : objc_object {
Copy the code

isa

Source code analysis

Exploring objc_Object, we know that objc_object is made up of isa_t ISA and member variables in memory. View the source code for ISA_t

union isa_t {
    uintptr_t bits;

private:
    Class cls;

public:
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

Copy the code
  1. Isa is aUnion (common body)
  2. Isa in the new version of memory after optimization, throughA domainThe way from the originalA 64 - bitIt simply acts as a class pointer and becomes free space to store other information. For example, in the x86 architecture, the middle 44 bits store the address of the class pointer, and the other bits store the information of associated objects, weak references, hash tables, etc., to a greater extentSave memory space.
  3. Among themISA_MASKAs amaskIn ISA_BITFIELDRedundant information about bit-fieldsFilter out theshiftcls, the value of the class pointer.
define ISA_MASK        0x00007ffffffffff8ULL
define ISA_BITFIELD
      uintptr_t nonpointer        : 1;
      uintptr_t has_assoc         : 1; 
      uintptr_t has_cxx_dtor      : 1;
      uintptr_t shiftcls          : 44; 
      uintptr_t magic             : 6; 
      uintptr_t weakly_referenced : 1;
      uintptr_t unused            : 1;
      uintptr_t has_sidetable_rc  : 1;
      uintptr_t extra_rc          : 8
Copy the code

We can see their flow

Graph TD object corresponds to objc_object --> objc_object is made up of ISA --> ISA points to objc_Class isa points to objc_Class --> Objc_Class inherits from objc_Object objc_Class inherits from objc_Object --> Objc_object is made of ISA

Prints ISA memory information

The isa of an object points to a class. What does the ISA of a class point to?

In this example we explore the memory of XXPerson

XXPerson *p = [XXPerson alloc];
NSLog(@"%@",p);
Copy the code
  1. pTo print out the objectMemory address
  2. x/4gxCalculates the memory address to which the current object pointsFour adjacent memory addresses
  3. p/xIsa address & ISA_MASK calculatedThe pointer address of shiftcls (class object)
  4. poPrint out the class objectDescription information
  5. According to theStep 3The calculated address of the class object,Repeat steps 2-4

  • p->isa == p.class == 0x0000000100008270 == XXPerson
  • p.class->isa == p.class.class == 0x0000000100008248 == XXPerson
  • (p.class->isa)->isa == p.class.class.class == 0x00007fff88c65ca0 == NSObject
  • ((p.class->isa)->isa)->isa == p.class.class.class.class == 0x00007fff88c65ca0 == NSObject

Metalclass (metal Class)

The ISA of the class refers to the metaclass

We can see that the printed memory address of P.lass and p.class.class is different, but the description printed through Po is the same, which is XXPerson.

Open MacOView, search the symbol table for XXPerson, and find _OBJC_METACLASS_$_XXPerson, where the type corresponds to the metaclass ->isa

Root Metal class

The ISA of the metaclass refers to the root metaclass

The description printed by the root metaclass is NSObject, and after that isa points to 0x00007FFF88C65CA0, the description printed by Po is NSObject.

  • A metaclasswithNSObject metaclassAddress to point to0x00007fff88c65ca0isconsistentthe
  • A metaclasswithNSObject classAddress to point to0x00007fff88c65cc8different
  • A metaclass isaPointing to orA metaclass

conclusion

The NSObject

  • Instances of the isa–>class
  • Class of isa–>The metaclass
  • Isa metaclass–>A metaclass
  • Isa of the root metaclass–>oneself

NSObject

  • NSObject–>The NSObject class
  • The NSObject class–>NSObject metaclass
  • NSObject metaclass–>oneself
  • NSObject metaclassnamelyA metaclass

superclass

Metaclasses have inheritance relationships

Class pMetaClass = object_getClass(LGPerson.class);
Class psuperClass = class_getSuperclass(pMetaClass);
NSLog(@"%@ - %p",psuperClass,psuperClass);

Class tMetaClass = object_getClass(LGTeacher.class);
Class tsuperClass = class_getSuperclass(tMetaClass);
NSLog(@"%@ - %p",tsuperClass,tsuperClass);
Copy the code

Print the result

LGPerson is the parent class of LGTeacher. It can be seen from the printed results above that there is an inheritance relationship between metaclasses and the parent class of metaclasses is the metaclass of the parent class.

NSObject’s parent class is nil

Class nsuperClass = class_getSuperclass(NSObject.class);
NSLog(@"%@ - %p",nsuperClass,nsuperClass);
Copy the code

Print the result

The parent of the NSObject metaclass is the NSObject class

In the code

Class rnsuperClass = class_getSuperclass(metaClass);
NSLog(@"%@ - %p",rnsuperClass,rnsuperClass);
Copy the code

Print the result

This is the same address as the NSObject class that was printed up here, but metaclases are also classes, on the other hand, so in their inheritance diagram, they still end up pointing to NSObject, everything is NSObject.

A diagram of class and metaclass inheritance

Apple official documentation ISA goes bitmap and class, metaclass inheritance diagram

class_data_bits_t bits

First, let’s look at the objc_class code for the metaclass

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
Copy the code

Class_data_bits_t bits Indicates the location of an address

Methods, member variables, protocols, and so on are stored in bits. We can use address offsets to locate bits in class objects. What we know is that class objects inherit from ObjC_Object, so the first member variable isa is 8 bytes, superclass is 8 bytes, However, we do not know the size of the cache_t cache. View the source code, by removing methods, global variables and other objects do not take up memory space code, extract the following part of the code

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};Copy the code

Since the lower part of the structure is a union and shares memory, simple calculations show that cache_t cache occupies 16 bytes of memory 8 + 8. Add the isa and superclass above to the class_datA_bits_t bits address offset by 32 bytes

Member variable information

Perform the following steps to print the memory

  1. x/4gxLgperson.class, to get the head of memory0x100008380
  2. p/x 0x100008380 + 0x20, the offset memory is obtained0x00000001000083a0
  3. Strong type p(class_data_bits_t *)0x00000001000083a0, the LLDB variable $97 is obtained
  4. throughp $97->data()To obtainclass_data_bits_t bitsClass_rw_t *) $98 = 0x0000000101233CA0
  5. p $98->properties()Gets class member information
(const property_array_t) $100 = {
  list_array_tt<property_t, property_list_t, RawPtr> = {
     = {
      list = {
        ptr = 0x0000000100008260
      }
      arrayAndFlag = 4295000672
    }
  }
}
Copy the code
  1. p $100.list
  2. p $101.ptr
  3. p * $113
p *$113
(property_list_t) $114 = {
  entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)
}
Copy the code
  1. The print result is an array, so it passesgetMethod, p$114.get(0)Print memory
(property_t) $115 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
Copy the code

methods

  1. x/4gxLgperson. class, which prints the memory address of the class object
0x100008380: 0x00000001000083a8 0x000000010036a140
0x100008390: 0x00000001012340f0 0x0002802800000003
Copy the code
  1. Enter P /x 0x100008380 +0x20To obtainClass_data_bits_t bits Specifies the offset address of 32 bytes
$117 = 0x00000001000083a0
Copy the code
  1. Enter p (class_datA_bits_t *) 0x00000001000083A0 to strongly change the type toClass_data_bits_t pointer
(class_data_bits_t *) $118 = 0x00000001000083a0
Copy the code
  1. Type p $119 – >methods()To obtainMethods information
(const method_array_t) $120 = {
  list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
     = {
      list = {
        ptr = 0x0000000100008160
      }
      arrayAndFlag = 4295000416
    }
  }
}
Copy the code
  1. Type p $120. The list
(const method_list_t_authed_ptr<method_list_t>) $121 = {
  ptr = 0x0000000100008160
}
Copy the code
  1. p $121.ptr
(method_list_t *const) $122 = 0x0000000100008160
Copy the code
  1. Type p * $122
(method_list_t) $123 = {
  entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 6)
}
Copy the code
  1. Type p $123.get(0).big(), includingget(0)To get the first element of the array’s method_t,big()Print method information
(method_t::big) $125 = {
  name = "sayNB"
  types = 0x0000000100003f77 "v16@0:8"
  imp = 0x0000000100003d40 (KCObjcBuild`-[LGPerson sayNB])
}
Copy the code