This is the 4th day of my participation in the August More Text Challenge

A,isaAnalyze to metaclass

In the previousIsa analysisAnd we analyze thatObject isa & ISA_MASKgetLRPersonClass, is there any in that classisaIt is, the classisaWhat does it point to?Pick up from the previous chapter on thisLRPersonThe class againx/4gxView memory and print outClass isa & ISA_MASKI also gotLRPersonClass. That is to say,0x0000000100008388 0x0000000100008360All point toLRPerson.

You can see that the class also opens up memory for ISA and other information. So let’s guess: classes can open up memory just like objects, and there is more than one class. Let’s try to verify that

Check out the following code print:You can see that the class object points to the same memory address0x100008388, that topClass isa & ISA_MASKTo get the0x0000000100008360What is it?

At this point with the aid ofMachOViewView executable filesYou can see in the symbol table that there’s aMETACLASSAnd this isThe metaclass.Metaclasses are system-generated and compiled.

The flow can be analyzed here: object ISA -> class ISA -> metaclass

Second,isaGo bitmap and inheritance chain

1.isaWalk a

The above analysis shows thatThe metaclass, thenIsa metaclassWhat about the process?throughlldbStep by step analysis of the print, observe the following conclusions:

  • Object the isa -> class
  • Class isa -> The metaclass
  • The metaclass isa -> A metaclass
  • A metaclass isa -> A metaclass
  • The root class isa -> A metaclass

Through the code verification:

// NSObject instance object
NSObject *object1 = [NSObject alloc];
/ / NSObject class
Class cass = object_getClass(object1);
/ / NSObject metaclass
Class metaClass = object_getClass(class);
// NSObject root metaclass
Class rootMetaClass = object_getClass(metaClass);
// NSObject Root metaclass
Class rootRootMetaClass = object_getClass(rootMetaClass);
NSLog(@"\n-%p instance object \n-%p class \n-%p metaclass \n-%p root metaclass \n-%p root metaclass",object1,class,metaClass,rootMetaClass,rootRootMetaClass);
Copy the code

Get the print result:

-0x10104e840Instance objects-0x100357140-0x1003570f0The metaclass-0x1003570f0A metaclass-0x1003570f0Spikes metaclassCopy the code

Combined with analysisisaWalk the bitmap:

2,isaInheritance chain

In OC, classes are inherited, so is the metaclass root metaclass inherited? To explore, first create a class LRTeacher inherited from LRPerson, and then observe the following code print

/ / LRPerson metaclass
Class pMetaClass = object_getClass(LRPerson.class);
Class psuperClass = class_getSuperclass(pMetaClass);
NSLog(@"LRPerson metaclass parent: %@ - %p",psuperClass,psuperClass);

// LRTeacher -> LRPerson -> NSObject
// The metaclass also has an inheritance chain
Class tMetaClass = object_getClass(LRTeacher.class);
Class tsuperClass = class_getSuperclass(tMetaClass);
NSLog(@"LRTeacher metaclass parent: %@ - %p",tsuperClass,tsuperClass);

// NSObject root class special case
Class nsuperClass = class_getSuperclass(NSObject.class);
NSLog(@" Parent of root class: %@ - %p",nsuperClass,nsuperClass);

// Root metaclass -> NSObject
Class rnsuperClass = class_getSuperclass(object_getClass(NSObject.class));
NSLog(@" Parent of the root metaclass: %@ - %p",rnsuperClass,rnsuperClass);
Copy the code

The print result is as follows:

The parent of the LRPerson metaclass:NSObject - 0x1003570f0LRTeacher metaclass parent: LRPerson -0x100008360Parent of the root class :(null) -0x0The parent of the root metaclass:NSObject - 0x100357140
Copy the code

According to the printed results:

  • LRPerson metaclassInheritance inNSObject metaclassnamelyA metaclass
  • LRTeacher metaclassInheritance inLRPerson metaclass
  • NSObject root classInheritance innil
  • NSObject metaclassInheritance inNSObject root class

Through the above analysisisaBitmaps and inheritance chains combine to create a classic picture on apple’s official website

Third, the structure of the source analysis class

Object memoryThere areisaThere areMember variables, thenThe memory of a classWhat’s in it? We can see the root of the class in the source codeobjc_classIs a structure. objc_classThere are four member variables in the structure: hidden member variablesISAInheritance inobjc_object,superclassThe parent class,cache,bits. We’re already familiar with the first two, socacheandbitsWhat is it?

Class_rw_t contains the protocol for method attributes and so on

struct class_rw_t {
    ...
    const method_array_t methods() const{... }const property_array_t properties() const{... }const protocol_array_t protocols() const {...}
}
Copy the code

Now that we’re just going to objc_class, how do we get this memory data from the class?

Pointer and memory translation

It is not known how to get the structure of the current memory, so let’s look at Pointers and memory pans.

// Common pointer
int a = 10;
int b = 10;
NSLog(@"%d -- %p",a,&a);
NSLog(@"%d -- %p",b,&b);

// Object pointer
LRPerson *p1 = [LRPerson alloc];
LRPerson *p2 = [LRPerson alloc];
NSLog(@"%@ -- %p",p1,&p1);
NSLog(@"%@ -- %p",p2,&p2);
Copy the code

Observe the above code and get the print result as follows:

10 -- 0x7ffeefbff4cc
10 -- 0x7ffeefbff4c8
<LRPerson: 0x100714f90> -- 0x7ffeefbff4c0
<LRPerson: 0x10070e660> -- 0x7ffeefbff4b8
Copy the code

The common pointer points to the same memory space, but the two addresses are different. That’s the value copy. The addresses of two object Pointers are different, pointing to different memory space.

Look at thePointer to an array

// Array pointer
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);
Copy the code

Print result:

The address of &c[0] is the same as that of the first element. Memory addresses are contiguous and differ by 4 bytes, indicating that the current element type is 4 bytes. The pointer D +1 represents a shift by one step (the size of the current element type), in this case by 4 bytes, or by 8 bytes if the array is a pointer or object.

According to the analysis conclusion, we know that we can do the value operation through the translation of the pointer address, code verificationPrint result:

1
2
3
4
Copy the code

With this verification, can the class also fetch data by memory translation?

Fifth, class structure memory calculation

Print to view the memory status of the classAccording to the previous source code analysis class structure, you can know the first address0x0000000100008360isisaIt should be followed bysuperclass(Structure pointer is 8 bytes), verified in the screenshot0x0000000100357140forNSObject. The following iscacheandbits? Let’s start todaybitsAnd subsequent research of separate chapterscache.

From the structure of the classisaandsuperclassAre allClassThe type is the structure pointer8 bytes, want to pan through memory tobitsThe first thing to knowcacheThe size of the. Follow up belowcache_tSource: cache_tIs a structure whose size depends on the size of its internal member variables. We found thatcache_tThere are a lot of things in the structure, wheremethodsIn the method area,The global variableDoes not occupy the structure in the global region

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

The explicit_atomic

is a generic type whose true size depends on the uintptr_t that is 8 bytes. Originalpreoptcache = _originalPreoptCache = _originalPreoptCache = _originalPreoptCache = _originalPreoptCache

socache_tSize of the16 bytes.

To get herebitsNeeds to be offset from the first address of the class32 bytesnamely0x20Isa (8) + Superclass (8) + cache (16)). The first addressOffset 0 x20After the strong toclass_data_bits_t *You get the typebitsThe address of the

Vi.lldbAnalyze the attributes of the class

The above has been obtainedbitsWhere we areobjc_classSee the following line of code in the structureTry to getbits.data(), because it isPointer to theNeed to use->callWe found that$2->data()gotclass_rw_t *Type variable. Check it again$3Content found not previously mentionedmethods attribute agreementAnd so on. You have to go through$4.properties()To obtain,lldbThe analysis process is as follows:

Seven,lldbMethods for analyzing classes

The above analysis of classattribute, change theLRPerson, add some properties and methods

Continue through thelldbMethods for analyzing classesWhen analyzing methods, reducemethod_list_tLater, byget(index)Unable to get methods, this is different from properties

struct property_t {
    const char *name;
    const char *attributes;
};

struct method_t {
    ...
    struct big {
        SEL name;
        const char*types; MethodListIMP imp; }; . public: big &big()const{ ASSERT(! isSmall());return* (struct big *)this; }... };Copy the code

The property_t structure has two member variables that match the printed information, and the method_t structure has a big structure, so trying to print the big structure gives us the information we want to see.

reductionmethod_list_tAnd then you can seecount = 5, that is, there are 5 methods, print these 5 methods:And what we found is thatsaySomethingandhobby,nametheget setMethod,LRPersonThe class methodsay666But it didn’t becauseClass methodStored in theThe metaclassIn theMethods listIn the water.

Eight,lldbAnalyze the protocol of the class

Write an agreement,LRPersonMethods for complying with and implementing the protocol

inclass_rw_tI have one of these structuresprotocolsmethods

lldbAnalyze the protocol of the classWhen it get toprotocol_list_tDiscovery and propertiesproperty_list_t, methods,method_list_tThe structure is different. To viewprotocol_list_tThe structure of the body protocol_list_tIn the structurelist[0]forprotocol_ref_tType, get toprotocol_ref_tAfter the direct strong turnprotocol_tPrint out the details to seeinstanceMethods.instanceMethodsThe list of methods for the protocol, and in the list of methods we find the methods for the protocol we wrote earlier.