preface

Isa isa pointer to struct objc_class. Finally, we also have a preliminary understanding of the class inheritance and bitmap provided by apple official. Today we’re going to take a deep dive into the underlying structure of the class and take a deep look at apple’s official ISA bitmap.

1.0 Memory Offset

Before exploring the underlying structure of classes, take a look at Pointers and offsets. A pointer is an address variable that also requires memory address storage. The offset is relative to the header address, which is the address of an object or variable in memory.

1.0.1 Ordinary Pointers

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int a = 10;
        int b = 10;
        int* c=&a;
        int* d=&b;
        NSLog(@"%d--%p--%p--%p",a,c,&a,&c);
        NSLog(@"%d--%p--%p--%p",b,d,&b,&d);
    }
    return 0;
}
Copy the code

The output is as follows:

10--0x7ffeefbff1ec--0x7ffeefbff1ec--0x7ffeefbff1e0
10--0x7ffeefbff1e8--0x7ffeefbff1e8--0x7ffeefbff1d8
Copy the code

Analysis:

  • The value of A is 10, and the address is0x7ffeefbff1ecThat’s also the value of c, the value of B is 10, and the address is0x7ffeefbff1e8It’s also the value of D, which means that even though the value is the same, memory is allocated to store the address of A and the address of B respectivelyDifference between0x4 is four bytes, and the difference depends on the type of A,A is an int, 4 bytes.
  • The value of c is 0x7FFeEFbff1ec, and the address is0x7ffeefbff1e0, the value of d is 0x7ffeefbff1e8 and the address is0x7ffeefbff1d8, the difference between the address of C and the address of D 0x8 is 8 bytes, c is a pointer,Pointers are 8 bytes long.
  • A, B, C, and D are all variables.Variables are stored in the stack area.The stack areaThe address of theHigh address to low address, a address 0x7ffeefbff1ecIs greater thanB’s address 0x7ffeefbff1e8.

1.0.2 Object Pointers

int main(int argc, const char * argv[]) {
    @autoreleasepool {
       LGPerson *p1 = [LGPerson alloc];
       LGPerson *p2 = [LGPerson alloc];
       NSLog(@"%@ -- %p",p1,&p1);
       NSLog(@"%@ -- %p",p2,&p2);
    }
    return 0;
}
Copy the code

The output is as follows:

<LGPerson: 0x100626410> -- 0x7ffeefbff1e8
<LGPerson: 0x100625440> -- 0x7ffeefbff1e0
Copy the code

Analysis:

  • objectThe memory isThe heap area, the localvariableThe memory isThe stack area.
  • The heap areaThe address isLow address to high address.The stack areaThe address isHigh address to low address. Address of p1 pointer0x7ffeefbff1e8Address greater than p2 pointer0x7ffeefbff1e0.Pointer to theIt’s for the addressvariable, this variable is inThe stack area, that is, Pointers are stored in the stack area. The value of p1 0x100626410 is less than the value of P2 0x100625440 is the address of p2.objectIs stored inThe heap area.

The illustration below

1.0.3 Array Pointers

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int c[4] = {1.2.3.4};
        int *d   = c;
        NSLog(@"%p - %p - %p",&c,&c[0],&c[1]);
        NSLog(@"%p - %p - %p",d,d+1,d+2);

        for (int i = 0; i<4; i++) {
            int value =  *(d+i);
            NSLog(@"%d",value); }}return 0;
}
Copy the code

The output is as follows:

0x7ffeefbff1e0 - 0x7ffeefbff1e0 - 0x7ffeefbff1e4
0x7ffeefbff1e0 - 0x7ffeefbff1e4 - 0x7ffeefbff1e8
1
2
3
4
Copy the code

Analysis is as follows:

  • An array ofIs an array elementThe first address, i.e.,&cand&c[0]
  • The offset of each element in the array, based on the current element’s data type
  • The address of the element in an array can be the first address +n* type size, which is in the arrayThe element typeMust be the same

Conclusion:

  • variableThe memory isThe stack area.objectThe memory isThe heap area.Pointer to theIt’s an address storevariableIn theThe stack area.
  • The stack areaHigh address to low address, heap low address to high address.
  • Memory addressThat’s the memory elementThe first address.
  • Memory migrationAccording toFirst address + offset valueMethod to obtain the address of the dependent variable.

2.0 ISA analysis

We analyze isa to get the value of shiftcls in ISA, that is, the value of the class pointer, to get the class object associated with ISA. We find that the ISA of an instance object is associated with a class object, and the ISA of a class object is associated with a class object, called a metaclass. Let’s look at this in detail.

2.0.1 Classes and metaclasses

  Class class1 = [LGPerson class];
    Class class2 = [LGPerson alloc].class;
    Class class3 = object_getClass([LGPerson alloc]);
    Class class4 = [LGPerson alloc].class;
    NSLog(@"\n%p-\n%p-\n%p-\n%p",class1,class2,class3,class4);
Copy the code

Output:

0x100008360-
0x100008360-
0x100008360-
0x100008360
Copy the code

Analysis: No matter how many alloc times, the memory address of the class object is the same, indicating that there is only one memory in memory to store the class object.

LGPerson *p = [LGPerson alloc]

(lldb) x/4gx p
0x1007055f0: 0x011d800100008365 0x0000000000000000
0x100705600: 0x0000000000000000 0x0000000000000000
(lldb) p/x 0x011d800100008365 & 0x00007ffffffffff8ULL
(unsigned long long) $1 = 0x0000000100008360
(lldb) po 0x0000000100008360
LGPerson

(lldb) x/4gx 0x0000000100008360
0x100008360: 0x0000000100008338 0x00007fff80691008
0x100008370: 0x0000000101805860 0x0002802c00000003
(lldb) p/x 0x0000000100008338 & 0x00007ffffffffff8ULL
(unsigned long long) $3 = 0x0000000100008338
(lldb) po 0x0000000100008338
LGPerson
Copy the code

Analysis: object P isa associated class object LGPerson, address 0x0000000100008360, but 0x0000000100008338 address is also LGPerson? We know that there is only one memory in memory for this class object, so what is 0x0000000100008338? Apple officially calls it a metaclass, and the system generates it automatically.

What is the isa associated with this metaclass, and how many layers of objects are associated with it? Then the LLDB above continues to explore

(lldb) x/4gx p
0x1007055f0: 0x011d800100008365 0x0000000000000000
0x100705600: 0x0000000000000000 0x0000000000000000
(lldb) p/x 0x011d800100008365 & 0x00007ffffffffff8ULL
(unsigned long long) $1 = 0x0000000100008360
(lldb) po 0x0000000100008360
LGPerson

(lldb) x/4gx 0x0000000100008360
0x100008360: 0x0000000100008338 0x00007fff80691008
0x100008370: 0x0000000101805860 0x0002802c00000003
(lldb) p/x 0x0000000100008338 & 0x00007ffffffffff8ULL
(unsigned long long) $3 = 0x0000000100008338
(lldb) po 0x0000000100008338
LGPerson

(lldb) x/4gx 0x0000000100008338
0x100008338: 0x00007fff80690fe0 0x00007fff80690fe0
0x100008348: 0x000000010053a640 0x0002e03500000003
(lldb) p/x 0x00007fff80690fe0 &  0x00007ffffffffff8ULL
(unsigned long long) $5 = 0x00007fff80690fe0
(lldb) po 0x00007fff80690fe0
NSObject

(lldb) x/4gx 0x00007fff80690fe0
0x7fff80690fe0: 0x00007fff80690fe0 0x00007fff80691008
0x7fff80690ff0: 0x0000000101807b80 0x0003e03100000007
(lldb) p/x 0x00007fff80690fe0 & 0x00007ffffffffff8ULL
(unsigned long long) $7 = 0x00007fff80690fe0
Copy the code

Analysis: LGPerson object isa- >LGPerson class ISA ->LGPerson metaclass ISA ->NSObject root metaclass

Now that we’re pointing to NSObject, let’s look at the ISA bitmap of NSObject. NSObject* myobjc=[NSObject alloc] LLDB debug as follows

(lldb) x/4gx myobjc
0x103098400: 0x011dffff80691009 0x0000000000000000
0x103098410: 0x63756f54534e5b2d 0x7765695672614268
(lldb) p/x 0x011dffff80691009 & 0x00007ffffffffff8ULL
(unsigned long long) $1 = 0x00007fff80691008
(lldb) po 0x00007fff80691008
NSObject

(lldb) x/4gx 0x00007fff80691008
0x7fff80691008: 0x00007fff80690fe0 0x0000000000000000
0x7fff80691018: 0x000000010052a160 0x0001801000000003
(lldb) p/x 0x00007fff80690fe0 & 0x00007ffffffffff8ULL
(unsigned long long) $3 = 0x00007fff80690fe0
(lldb) po 0x00007fff80690fe0
NSObject

(lldb) x/4gx 0x00007fff80690fe0
0x7fff80690fe0: 0x00007fff80690fe0 0x00007fff80691008
0x7fff80690ff0: 0x0000000103007d90 0x0003e03100000007
(lldb) p/x 0x00007fff80690fe0 & 0x00007ffffffffff8ULL
(unsigned long long) $5 = 0x00007fff80690fe0
(lldb) po 0x00007fff80690fe0
NSObject
Copy the code

NSObject isa isa isa isa NSObject Isa isa NSObject isa isa NSObject metaclass itself is the root metaclass.

The above analysis is easier to understand in the previous diagram than LGPerson.

2.0.2 Class inheritance

We have analyzed the ISA relation of the class above, but is the ISA relation of the inherited class also like this, and how is the ISA relation of the inherited class parent? We’ll create a new object LGTeacher *t = [LGTeacher alloc]; LGTeacher inherits from LGPerson, LLDB to debug isa associations.

(lldb) x/4gx t
0x103836e70: 0x011d800100008315 0x0000000000000000
0x103836e80: 0x0000000000000000 0x0000000000000000
(lldb) p/x 0x011d800100008315 & 0x00007ffffffffff8ULL
(unsigned long long) $8 = 0x0000000100008310
(lldb) po 0x0000000100008310
LGTeacher

(lldb) x/4gx 0x0000000100008310
0x100008310: 0x00000001000082e8 0x0000000100008360
0x100008320: 0x00007fff20282aa0 0x0000802c00000000
(lldb) p/x 0x00000001000082e8 & 0x00007ffffffffff8ULL
(unsigned long long) $10 = 0x00000001000082e8
(lldb) po 0x00000001000082e8
LGTeacher

(lldb) x/4gx 0x00000001000082e8
0x1000082e8: 0x00007fff80690fe0 0x0000000100008338
0x1000082f8: 0x000000010061cf20 0x0002e03500000003
(lldb) p/x 0x00007fff80690fe0 & 0x00007ffffffffff8ULL
(unsigned long long) $12 = 0x00007fff80690fe0
(lldb) po 0x00007fff80690fe0
NSObject
Copy the code

Analysis: : LGTeacher object isa >LGTeacher class ISA >LGTeacher metaclass ISA >NSObject root metaclass. So see with LGTeacher’s ISA and LGPerson’s ISA is the same, LGTeacher and LGPerson have no other relationship?

Continue demo exploration:

     / / LGPerson metaclass
    Class pMetaClass = object_getClass(LGPerson.class);
    Class psuperClass = class_getSuperclass(pMetaClass);
    NSLog(@"Metaclass: %@ - %p Parent metaclass: %@ - %p",pMetaClass,pMetaClass,psuperClass,psuperClass);
    
    / / LGTeacher metaclass
    Class tMetaClass = object_getClass(LGTeacher.class);
    Class tsuperClass = class_getSuperclass(tMetaClass);
    NSLog(@"Metaclass: %@ - %p Parent metaclass: %@ - %p",tMetaClass,tMetaClass,tsuperClass,tsuperClass);
    
    // NSObject root metaclass parent class
    Class nsuperClass = class_getSuperclass(NSObject.class);
    NSLog(@"%@ - %p",nsuperClass,nsuperClass);
Copy the code

The output is as follows:

Metaclass: LGPerson -0x100008338Metaclass parent: NSObject -0x7fff80690fe0Metaclass: LGTeacher -0x1000082e8Metaclass parent: LGPerson -0x100008338
(null) - 0x0
Copy the code

The parent address of the LGTeacher metaclass is 0x100008338, the address of the LGTeacher metaclass is 0x100008338, and the address of the LGTeacher metaclass is 0x100008338. The LGTeacher metaclass inherits from the LGPerson metaclass and the NSObject root metaclass inherits from nil.

The inheritance relationship ISA is shown below:

Compare apple’s official ISA with the above analysis, and it becomes clear:

Structure analysis of class 3.0

Isa isa isa isa Isa Isa Isa Isa Isa Isa Isa Isa Isa Isa Isa Isa Isa Isa Isa Isa Isa Isa Isa isa isa isa isa isa isa Objc4-818.2 objC_class = objC4-818.2

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
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};
Copy the code

Objc_class inherits objc_Object, which has only one member variable isa. The member variables in objC_class are ISA, superclass, Cache, and bits. Superclass is a structure pointer to objc_class with 8 bytes.

Find the definition of cache_t:

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

Analysis:

  • cache_tIs a structure type with two member variables _bucketsAndMaybeMask and a union.
  • _bucketsAndMaybeMaskNo operator is uintptr_tLong integers account for 8 bytes.
  • A consortiumThere are two member variables in thereThe structure of the bodyand _originalPreoptCacheThe memory size of the union is determined by the maximum variable type in the member variable.

-_originalPreoptCache is a structure pointer of 8 bytes. The structure contains _maybeMask, _flags, _occupied. _maybeMask is the uint32_t of 4 bytes, _flags and _occupied are the Uint16_t of 2 bytes each, and the structure size is 8 bytes.

  • cache_tThe memory size of 8+8 or 8+4+2+2 is 16 bytes.

Objc_class summary

  • The address of the first element in the structure is thisThe first address of a structure
  • Isa’s memory address is the first address of objc_class, which is 8 bytes
  • The memory address of a superclass is the first address+0x8, 8 bytes
  • The memory address of the cache is the first address +0x10, 16 bytes
  • The memory address of bits is the first address +0x20

3.1 –

Today we’re going to focus on what’s stored in bits, and notice that we’ve been analyzing classes, and bits are in classes. Bits is a class_data_bits_t struct. The source code is too long.

struct class_data_bits_t {
    friend objc_class;// the friend keyword sets objc_class as a friend structure
    // Values are the FAST_ flags above.
    uintptr_t bits;Unsigned long integer 8 bytes
private:
   // Omit some struct methods
public:
   //data stores attributes, methods, protocols, etc
    class_rw_t* data() const {
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }
    // Store member variables
    const class_ro_t *safe_ro() const {
    class_rw_t *maybe_rw = data();
    if (maybe_rw->flags & RW_REALIZED) {
        // maybe_rw is rw
        return maybe_rw->ro();
    } else {
        // maybe_rw is actually ro
        return(class_ro_t *)maybe_rw; }}// Omit some struct methods
};
Copy the code

Analysis:

  • class_data_bits_tThere is only one long integer member variable in the structurebits
  • The long integer variable bits has no desire to explore, but finds a pointclass_rw_tStructure pointer todata()The programmer’s intuition about what data should store.

Take a look at the class_rw_T structure

  uint32_t flags;
    uint16_t witness;
#if SUPPORT_INDEXED_ISA
    uint16_t index;
#endif
    explicit_atomic<uintptr_t> ro_or_rw_ext;
    Class firstSubclass;
    Class nextSiblingClass;
    / / to omit...
    class_rw_ext_t *ext() const {
        / / to omit...
    }
    class_rw_ext_t *extAllocIfNeeded() {
       / / to omit...
    }

    class_rw_ext_t *deepCopy(const class_ro_t *ro) {
        return extAlloc(ro, true);
    }
    // Member variables
    const class_ro_t *ro() const {
        / / to omit...
    }

    void set_ro(const class_ro_t *ro) {
        / / to omit...
    }
    / / method
    const method_array_t methods() const {
     / / to omit...
    }

    const property_array_t properties() const {
         / / to omit...
    }

    const protocol_array_t protocols() const {
    / / to omit...
    }
Copy the code

Analysis:

  • The class_rw_t structure has familiar methods(), properties(),protocols()

3.2 Attribute Acquisition

Example verify that class_rw_t stores methods, attributes, and protocols. Create a demo like this and instantiate the LGPerson demo like this:

@protocol LGPersonDegete<NSObject>

-(void)testLGperson;

@end
@interface LGPerson : NSObject<LGPersonDegete>{
    NSString *subject;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *hobby;

- (void)sayNB;
+ (void)say666;
@end
Copy the code

LLDB debugging gets properties:

KCObjcBuild was compiled with optimization - stepping may behave oddly; variables may not be available.
(lldb) p/x LGPerson.class
(Class) $0 = 0x0000000100008380 LGPerson
(lldb) p/x 0x0000000100008380 + 0x20  // Note: the first address +0x20 offset is class_datA_bits_t address
(long) $1 = 0x00000001000083a0
(lldb) p (class_data_bits_t*)$1
(class_data_bits_t *) $2 = 0x00000001000083a0
(lldb) p $2->data()                    // Comment: get data
(class_rw_t *) $3 = 0x0000000100723c30
(lldb) p $3->properties()             // Comment: get attributes in data
(const property_array_t) $4 = {
  list_array_tt<property_t, property_list_t, RawPtr> = {
     = {
      list = {
        ptr = 0x0000000100008260
      }
      arrayAndFlag = 4295000672
    }
  }
}
(lldb) p $4.list                     // Comment: Get the property list
(const RawPtr<property_list_t>) $5 = {
  ptr = 0x0000000100008260
}
(lldb) p $5.ptr                      // Comment: Get the attribute list PTR
(property_list_t *const) $6 = 0x0000000100008260
(lldb) p *$6
(property_list_t) $7 = {             // Comment: Get attribute list information
  entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)
}
(lldb) p $7.get(0)                   // Comment: the first attribute
(property_t) $8 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
(lldb)  p $7.get(1)                  // Comment: second attribute
(property_t) $9 = (name = "hobby", attributes = "T@\"NSString\",C,N,V_hobby")
(lldb) 
Copy the code

Analysis: Comments illustrate the LLDB debugging process. LGPerson->class_data_bits_t->data->properties->list->ptr->get

3.3 Method Acquisition

LLDB debugging is as follows:

(lldb) p $3->methods()              // Comment: get method
(const method_array_t) $10 = {
  list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
     = {
      list = {
        ptr = 0x0000000100008160
      }
      arrayAndFlag = 4295000416
    }
  }
}
(lldb) p $10.list                  // Comment: Get a list of methods
(const method_list_t_authed_ptr<method_list_t>) $11 = {
  ptr = 0x0000000100008160
}
(lldb) p $11.ptr                  // Comment: Get method list PTR
(method_list_t *const) $12 = 0x0000000100008160
(lldb) p *$12
(method_list_t) $13 = {
  entsize_list_tt<method_t, method_list_t, 4294901763.method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 6)
}
(lldb) p $13.get(0).big()        // Comment: get the first method
(method_t::big) $15 = {
  name = "sayNB"
  types = 0x0000000100003f77 "v16@0:8"
  imp = 0x0000000100003d40 (KCObjcBuild` - [LGPerson sayNB])} (LLDB) p $13. Get (1). The big () / / comment: Get the second method (method_t::big) $16 = {name = "hobby" types = 0x0000000100003F6f "@16@0:8" IMP = 0x0000000100003DB0 (KCObjcBuild`-[LGPerson hobby])
}
(lldb) p $13.get(2).big()
(method_t::big) $17 = {
  name = "setHobby:"
  types = 0x0000000100003f8b "v24@0:8@16"
  imp = 0x0000000100003de0 (KCObjcBuild`-[LGPerson setHobby:]) } (lldb) p $13.get(3).big() (method_t::big) $18 = { name = "init" types = 0x0000000100003f6f "@16@0:8" imp = 0x0000000100003ce0 (KCObjcBuild`-[LGPerson init])
}
Copy the code

Analysis:

  • Unlike getting properties(), getting methods is actually getting method_t, which has a big() method to get method.
  • Comments mark the process of LLDB debugging.LGPerson->class_data_bits_t->data->methods()->list->ptr->get(0).big().
  • Watch carefully LGPerson, I sayNB and say666 defines two methods, through LLDB debugging found LGPerson. Only sayNB class class () method without say666 () method, according to? SayNB is ()Instance method it's in the class, thenObject methodssay666()Where is it? Watch my next blog for a detailed analysis.

3.4 Obtaining Protocols

(lldb) p/x LGPerson.class
(Class) $15 = 0x0000000100008898 LGPerson
(lldb) p/x 0x0000000100008898 + 0x20
(long) $16 = 0x00000001000088b8
(lldb) p/x (class_data_bits_t*)$16
(class_data_bits_t *) $17 = 0x00000001000088b8
(lldb) p $17->data()
(class_rw_t *) $18 = 0x0000000100707990
(lldb) p $18->protocols()
(const protocol_array_t) $19 = {
  list_array_tt<unsigned long, protocol_list_t, RawPtr> = {
     = {
      list = {
        ptr = 0x0000000100008348
      }
      arrayAndFlag = 4295000904
    }
  }
}
(lldb) p $19.list
(const RawPtr<protocol_list_t>) $20 = {
  ptr = 0x0000000100008348
}
(lldb) p $20.ptr
(protocol_list_t *const) $21 = 0x0000000100008348
(lldb) p *$21
(protocol_list_t) $22 = (count = 1, list = protocol_ref_t [] @ 0x00007fa105c5eae8)
(lldb) p $22.list[0]       Protocol_list_t = list[0];
(protocol_ref_t) $23 = 4295002352
(lldb) p (protocol_t*)$23       / / turn protocol_ref_t protocol_t strong
(protocol_t *) $24 = 0x00000001000088f0
(lldb) p $24
(protocol_t *) $24 = 0x00000001000088f0
(lldb) p *$24
(protocol_t) $25 = {
  objc_object = {
    isa = {
      bits = 4298547400
      cls = Protocol
       = {
        nonpointer = 0
        has_assoc = 0
        has_cxx_dtor = 0
        shiftcls = 537318425
        magic = 0
        weakly_referenced = 0
        unused = 0
        has_sidetable_rc = 0
        extra_rc = 0
      }
    }
  }
  mangledName = 0x0000000100003c3a "LGPersonDegete"
  protocols = 0x0000000100008430
  instanceMethods = 0x0000000100008448
  classMethods = 0x0000000000000000
  optionalInstanceMethods = 0x0000000000000000
  optionalClassMethods = 0x0000000000000000
  instanceProperties = 0x0000000000000000
  size = 96
  flags = 0
  _extendedMethodTypes = 0x0000000100008468
  _demangledName = 0x0000000000000000
  _classProperties = 0x0000000000000000
}
(lldb) 
Copy the code

Analysis:

  • Protocol to obtain a complex need to structure the source code analysis, first to obtainStructure protocol_list_tGets a member variable in the protocol_list_t structurelist[0], the member variable is protocol_ref_t,Cast protocol_ref_tforprotocol_t, and return the protocol_t value
  • LGPerson – > class_data_bits_t – > data – > protocol () – > list – > PTR [0] – > – > list are strong protocol_t *

3.5 Obtaining member variables

Class_rw_t does get methods, attributes, and protocols, but does not. The subject variable in our demo does not get methods, attributes, and protocols. Where is it stored? There is a method to get ro() in class_rw_t, which LLDB explores.

(lldb) p/x LGPerson.class
(Class) $27 = 0x0000000100008898 LGPerson
(lldb) p/x 0x0000000100008898 + 0x20
(long) $28 = 0x00000001000088b8
(lldb) p (class_data_bits_t*)$28
(class_data_bits_t *) $29 = 0x00000001000088b8
(lldb) p $29->data()
(class_rw_t *) $30 = 0x0000000100707990
(lldb) p $30->ro()
(const class_ro_t *) $31 = 0x0000000100008250
(lldb) p *$31
(const class_ro_t) $32 = {
  flags = 0
  instanceStart = 8
  instanceSize = 32
  reserved = 0
   = {
    ivarLayout = 0x0000000000000000
    nonMetaclass = nil
  }
  name = {
    std::__1::atomic<const char *> = "LGPerson" {
      Value = 0x0000000100003c31 "LGPerson"
    }
  }
  baseMethodList = 0x0000000100008298
  baseProtocols = 0x0000000100008348
  ivars = 0x0000000100008360
  weakIvarLayout = 0x0000000000000000
  baseProperties = 0x00000001000083c8
  _swiftMetadataInitializer_NEVER_USE = {}
}
(lldb) p $32.ivars
(const ivar_list_t *const) $33 = 0x0000000100008360
(lldb) p *$33
(const ivar_list_t) $34 = {
  entsize_list_tt<ivar_t, ivar_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 32, count = 3)
}
(lldb) p $34.get(0)
(ivar_t) $35 = {
  offset = 0x00000001000087e0
  name = 0x0000000100003caf "subject"
  type = 0x0000000100003e0d "@\"NSString\""
  alignment_raw = 3
  size = 8
}
(lldb) 
Copy the code

Analysis:

  • Member variablessubjectIn ro ()In the
  • LGPerson->class_data_bits_t->data->ro()->ivars->get(0)

Conclusion:

  • isaIs a point toobjc_classtheStructure pointer.objc_classinheritanceobjc_object.
  • The objc_class structure has member variablesIsa, Superclass, Cache, bits
  • bitsIt’s a class_data_bits_t struct, structPointer method data()You can getProperty list, method list, member variable list, protocol listAnd so on.
  • Member variablesPointer to the data() structurero()In the