current position:Home>07 - explore the underlying principles of IOS | several OC objects [instance object, class object, metaclass], ISA pointer of object, superclass, method call of object and the underlying essence of class

07 - explore the underlying principles of IOS | several OC objects [instance object, class object, metaclass], ISA pointer of object, superclass, method call of object and the underlying essence of class

2022-05-15 05:02:00Zhang without a story

Preface

Before , When we explore the principles of animation and rendering , We output several articles , Answer iOS How the animation is rendered , Doubts about how special effects work . We feel deeply that when system designers create these system frameworks , It's so wide open , also Deeply aware of the importance of understanding the underlying principles of a technology for working in this area . So we decided to Explore further iOS The task of the underlying principle , And This article serves as a summary , Modules to explore the underlying principles Make a summary , This leads to the sub description of the underlying principle of each sub module ( detailed )

before , Several output articles exploring the principles of animation and rendering are as follows :

Pre knowledge :

Based on pre knowledge , We learned more about iOS The principle of imaging :03-iOS Various rendering frameworks and iOS Layer rendering principle

Based on the knowledge of the previous articles , We finally learned iOS The process and principle of animation rendering

Last , We are also based on Ring learning Idea , Several related problems are explored :iOS OffScreen Rendering Off screen rendering principle iOS Page Caton principle and corresponding stability management

Our exploration of the underlying principles will output a total of (29 An article ):

One 、 summary

We explored in the previous article OC The article :Objective-C The essence of language in , Mentioned before OC It's a kind of object-oriented Advanced programming language . Therefore, this paper follows the pace of exploring the underlying principles of the previous article , Develop OC object-oriented The grammar of , Yes OC Of several object type To explore .
OC There are three main types of objects :

  • instance object ( Instance object )
  • class object ( Class object )
  • meta-class object ( Metaclass object )

also , We want to explore Class object (Class) Supplementary and extended syntax :Category( classification )

Two 、instance object

adopt OC Language program ,instance object Is through class alloc Out object , Every time you call alloc Will produce new instance object .
In the last article OC The nature of the object in , Through discussion NSObject Object's Underlying implementation Memory layout Understand through inheritance Subclass 、 Grandchildren Memory layout ... Is to explore instance object The beginning of the underlying process . Now briefly review the conclusions of previous exploration , And continue to explore !
stay OC The nature of the object In this article , Our conclusion :

  • NSObject The underlying implementation of :
     At present, the format in the header file officially exposed :
    @interface NSObject <NSObject> { 
        Class isa   ; 
    }
    @end
    
     Short form :
    
    @interface NSObject <NSObject> { 
        objc_class isa   ; 
    }
    @end
    
     Structure objc_class The implementation of the :
    
    struct objc_class { 
        private: 
        isa_t isa; 
        public:
        Class superclass;
    
        const char *name;
    
        uint32_t version;
    
        uint32_t info;
    
        uint32_t instance_size;
    
        struct old_ivar_list *ivars;
    
        struct old_method_list **methodLists;
    
        Cache cache;
    
        struct old_protocol_list *protocols;
    
        // CLS_EXT only
    
        const uint8_t *ivar_layout;
    
        struct old_class_ext *ext;
    
        ....    
    }
    
     Copy code 
  • Create a NSObject object Need at least 8 Bytes , stay 64 Bit system , The system has at least actually allocated 16 Bytes .
    • Need at least 8 Bytes Of memory ( To hold isa The pointer )

    • Actually allocated 16 Bytes Of memory ( Because when system developers design , Specifies the rules for memory allocation )

    • OC Object's The memory alignment parameter is 16

      • If there is not enough memory to allocate 16, Then give 16 Bytes
      • If the object needs to allocate more memory than 16, It is based on the data structure that can accommodate the object , With the closest 16 The least common multiple is the final allocation size
    • One OC Object layout in memory :

      • The system will open up a memory space in the heap to store the object
      • This space also contains Member variables and isa The pointer
      • Then... In the stack local variable Point to this storage space The address of

    • System Provides Two bottom layers API to developer Conduct Knowledge of memory allocation

       Create an instance object , At least how much memory is needed ?
      #import <objc/runtime.h>
      class_getInstanceSize([NSObject class]);
      
      
       Create an instance object , How much memory is actually allocated ?
      #import <malloc/malloc.h>
      malloc_size((__bridge const void *)obj);
      
       Copy code 

be-all OC Class Base class All are NSObject, and instance object It's essentially through [[Class alloc]init]...... Coming out

  • alloc: Allocate memory
  • init: initialization
int main(int argc, const char * argv[]) {

    @autoreleasepool { 
        // obj1、obj2 yes NSObject Of instance object ( Instance object )
        NSObject *obj1 = [[NSObject alloc]init];

        NSObject *obj2 = [[NSObject alloc]init];

        //  By printing it can be seen that , They are two different objects , Each occupies two different pieces of memory 
        NSLog(@"obj1:%p",obj1);

        NSLog(@"obj2:%p",obj2); 

    }

    return 0;

}
 
 Copy code 

image.png

We write four classes casually :( The inheritance relationship is as follows :)

  • Car : NSObject
    • Added a member : int _year
  • CarRun : Car
    • Added a way :
      • -(void)run;
  • BBA_BMW :CarRun
    • Added a member : ;
      • NSString*_nameplate;
  • BBA_BMW_RunFaster :BBA_BMW
    • Added a way :
      • -(void)runFaster;
@interface Car :NSObject{

@public

    int _year;

}

@end 


@implementation Car

- (instancetype)init{

    self = [super init];

    if (self) {

        _year = 1;

    }

    return self;

}

@end

@interface CarRun :Car

-(void)run;

@end
 


@implementation CarRun

-(void)run{

    NSLog(@"%s",__func__);

}

@end

    

@interface BBA_BMW :CarRun{

@public

    NSString*_nameplate;// Car nameplate  8 Bytes 

}

@end
 


@implementation BBA_BMW

@end
 


@interface BBA_BMW_RunFaster :BBA_BMW

-(void)runFaster;

@end
 

@implementation BBA_BMW_RunFaster

- (void)runFaster{

NSLog(@"%s",__func__);

}

@end

//main function :
int main(int argc, const char * argv[]) {

    @autoreleasepool {

       // obj1、obj2 yes NSObject Of instance object ( Instance object )

       NSObject *obj1 = [[NSObject alloc]init];   
       NSObject *obj2 = [[NSObject alloc]init]; 


       //  By printing it can be seen that , They are two different objects , Each occupies two different pieces of memory 

       NSLog(@"obj1:%p",obj1);

       NSLog(@"obj2:%p",obj2);

        

        //1. Create a   Base class  NSObject  Example   Distribute   Memory 

           

        NSLog(@"NSObject:getInstanceSize:%zd",class_getInstanceSize([NSObject class]));

        NSLog(@"obj-malloc_size:%zd",malloc_size((__bridge const void*)obj1));

        NSLog(@"=====================================================================");

        //2. Create a   Base class  NSObject  Subclasses of  Car  Example   Distribute   Memory 

        Car *car = [[Car alloc]init];

        NSLog(@"Car-getInstanceSize:%zd",class_getInstanceSize([Car class]));

        NSLog(@"Car-malloc_size:%zd",malloc_size((__bridge const void*)car));

        NSLog(@"=====================================================================");

        //3. Create a  Car  Subclasses of  CarRun  Example   Distribute   Memory 

        CarRun *car_run = [[CarRun alloc]init];

        NSLog(@"CarRun-getInstanceSize:%zd",class_getInstanceSize([CarRun class]));

        NSLog(@"CarRun-malloc_size:%zd",malloc_size((__bridge const void*)car_run));

        NSLog(@"=====================================================================");

        //4. Create a  CarRun  Subclasses of  BBA_BMW  Example   Distribute   Memory 

        BBA_BMW *bmw = [[BBA_BMW alloc]init];

        NSLog(@"BBA_BMW-getInstanceSize:%zd",class_getInstanceSize([BBA_BMW class]));

        NSLog(@"BBA_BMW-malloc_size:%zd",malloc_size((__bridge const void*)bmw));

        NSLog(@"=====================================================================");

        //5. Create a  CarRun  Subclasses of  BBA_BMW_RunFaster  Example   Distribute   Memory 

        BBA_BMW_RunFaster *bmw_runfaster = [[BBA_BMW_RunFaster alloc]init];

        NSLog(@"BBA_BMW_RunFaster-getInstanceSize:%zd",class_getInstanceSize([BBA_BMW_RunFaster class]));

        NSLog(@"BBA_BMW_RunFaster-malloc_size:%zd",malloc_size((__bridge const void*)bmw_runfaster));

        

        

    }

    return 0;

}
 Copy code 

adopt Print the results , Declaration of binding class We cannot draw a conclusion :

  • Add method , No effect Instance Object's memory allocation : Initialize an instance object , At least the required memory
  • Add member object , influence Instance Object's memory allocation : Initialize an instance object , At least the required memory

image.png

  • Instance object The actual memory required is related to its own member object , That is to say :instance Objects store information in memory about their own member objects , member object :
    • isa The pointer ( Base class NSObject Object exists inside )
    • Specific values of other member variables

3、 ... and 、Class object

1. Each class In memory There is one and only one Class object

We are exploring NSObject object When , See the underlying code :

    struct objc_class { 
        private: 
        isa_t isa; 
        public:
        Class superclass;

        const char *name;

        uint32_t version;

        uint32_t info;

        uint32_t instance_size;

        struct old_ivar_list *ivars;

        struct old_method_list **methodLists;

        Cache cache;

        struct old_protocol_list *protocols;

        // CLS_EXT only

        const uint8_t *ivar_layout;

        struct old_class_ext *ext;

        ....    
    }
 Copy code 

combination NSObject.h file :

@interface NSObject <NSObject> {

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Wobjc-interface-ivars"

    Class isa  OBJC_ISA_AVAILABILITY;

#pragma clang diagnostic pop
...
}
 Copy code 

From the first two pieces of code , It's not hard for us to know Base class NSObject There is one of them. Class Object of type :isa The pointer
We created four classes above , Code with inheritance relationship , adopt clang The instruction is converted to c++:

image.png

image.png

image.png

Combined with the previous inheritance relationship , And convert to c++ The specific situation after the underlying code ( Pictured above ), It's not hard for us to come to a conclusion :

  • Each class has and only one in memory class object
    • It can also be proved by printing the memory address :
                        Class objectClass1 = [object1 class];
                        Class objectClass2 = [object2 class];
                        Class objectClass3 = object_getClass(object1);
                        Class objectClass4 = object_getClass(object2);
                        Class objectClass5 = [NSObject class];
    
                        //  By printing it can be seen that , The above methods return the same class object , Memory addresses are the same 
                        NSLog(@"class - %p %p %p %p %p %d",
                                        objectClass1,
                                        objectClass2,
                                        objectClass3,
                                        objectClass4,
                                        objectClass5);
    
     Copy code 
    image.png
  • We can go through NSObject Of Class method Example method get Class object : image.png
    • + (Class)class
    • - (Class)class
  • We can also go through Runtime Of API get Class object :
    • Class _Nullable object_getClass(id _Nullable obj)  Copy code 
    • The API The effect is equivalent to + (Class)class- (Class)class
    image.png

Be careful :  class Method always returns a class object , So even if it is written like this, it will still return the class object

Class objectMetaClass2 = [[[NSObject class] class] class];
 Copy code 

image.png

2.Class Object stores information in memory

Let's look at Apple's official open source runtime Code we know ( Refer to this article for code acquisition and related exploration process :OC The essence of ),Class The underlying code is as follows :

image.png

image.pngimage.png

    struct objc_class { 
        private: 
        isa_t isa; 
        public:
        Class superclass;

        const char *name;

        uint32_t version;

        uint32_t info;

        uint32_t instance_size;

        struct old_ivar_list *ivars;

        struct old_method_list **methodLists;

        Cache cache;

        struct old_protocol_list *protocols;

        // CLS_EXT only

        const uint8_t *ivar_layout;

        //struct old_class_ext *ext;
        uint32_t size;

        const uint8_t *weak_ivar_layout;

        struct old_property_list **propertyLists;
        ....    
    }
 Copy code 

After checking the source code , It's not hard for us to come to a conclusion ,class Object stores information in memory :

    1. isa The pointer
    1. superclass The pointer
    1. Property information of class (@property)、 Class object method information (instance method
    • We go through runtimeAPI Traverse the methodLists Internal information , hear :struct old_method_list **methodLists Internal storage Class object method information (instance method
    image.png
    1. Class (protocol)、 Class member variable information (ivar
  • ....

3. summary

Yes instance Objects and Class Summary of objects :

  • isa The pointer : Each class In memory There is one and only one Class object ,isa The pointer
  • class Object stores information in memory :
      1. isa The pointer
      1. superclass The pointer
      1. Property information of class (@property)、 Class object method information (instance method
      1. Class (protocol)、 Class member variable information (ivar
    • ....
  • The value of the member variable Stored in the instance object : Is stored in the instance object , Because we only assign values to members when we create instance objects
  • Type of member object 、 value 、 name , Store in class In the object : however What is the name of the member variable , What type is it , Just have one . So it's stored in class In the object

3、 ... and 、meta-class object

1.meta-class Related functions

We are reading Apple's official open source objc Code , We found that there are several related to class Related internal implementation functions : image.png We have explored the more common instance- object class object Base class NSObjectsuperclass....
But when we looked through the source code, we found a meta-class.
Now let's get to know meta-class Let's search for metaclass, Find a return Class Object's objc_getMetaClass Implementation of function :

image.png Let's continue to jump in and have a look ISA() Implementation of function : image.png We can see from this code isa Object calls a function , and isa The pointer , Exist in itself class Inside :

image.png isa The internal definition is :

image.png function

inline Class isa_t::getDecodedClass(bool authenticated)  Copy code 

Internal implementation :

image.png

2.meta-class Relevant exploration conclusions

Sum up , It's not hard for us to come to a conclusion :

  • We can go through At present class Of isa The pointer Get metaClass
  • If current Class yes metaClass: be return Its own
  • metaClass Of metaClass Is it Oneself : image.png
  • We combine Class The internal structure of , It's not hard to come to a conclusion :
    • metaClass It's also class type (meta-class Objects and class The memory structure of the object is the same )
    • metaClass It's a special kind of Of class type ( And others Class Objects may have different uses )
  • meta-class The list of stored methods is Class method information (class method)image.pngimage.png
  • meta-class Of superclass by NSObject Type of meta-class
  • meta-class Of superclass Of superclass by Base class NSObject( Non metaclass )
  • meta-class Of superclass Of superclass Of superclass, That is to say Base class NSObject( Non metaclass ) Of superclass Of by nil

image.png

  • Base class NSObject( Non metaclass ) Of superclass by nil
  • Add , obtain meta-class Function of except function objc_getMetaClass, also object_getClass

3.meta-class Brief summary

meta-class Objects and class The memory structure of the object is the same , But for different purposes , The information stored in memory mainly includes :

  • isa The pointer
  • superclass The pointer
  • Class method information (class method)
  • ....

Four 、isa and superclass

1.isa The pointer

Through the previous Introduction , We learned that : Of each class Instance object Class object Metaclass object There is one. isa The pointer

void test11(void){

    Class animalMetaCls =  getMetaClassFromClass([BBA_BMW_RunFaster class]);

    NSLog(@"superclass:%@",[BBA_BMW_RunFaster superclass]);

    NSLog(@"superclass-superclass:%@",[[BBA_BMW_RunFaster superclass] superclass]);

    NSLog(@"superclass-superclass-superclass:%@",[[[BBA_BMW_RunFaster superclass] superclass] superclass]);

    NSLog(@"superclass-superclass-superclass-superclass:%@",[[[[BBA_BMW_RunFaster superclass] superclass] superclass] superclass]);

    NSLog(@"superclass-superclass-superclass-superclass-superclass:%@",[[[[[BBA_BMW_RunFaster superclass] superclass] superclass] superclass] superclass]);

    NSLog(@"====================");

    NSLog(@"metaClass:%@",animalMetaCls);

    NSLog(@"metaClass-superclass:%@======metaClass-superclass_class_isMetaClass:%d",[animalMetaCls superclass],class_isMetaClass([animalMetaCls superclass]));

    NSLog(@"metaClass-superclass-superclass:%@======metaClass-superclass-superclass_class_isMetaClass:%d",[[animalMetaCls superclass]superclass],class_isMetaClass([[animalMetaCls superclass]superclass]));

    NSLog(@"====================");

    NSLog(@"metaClass-superclass-superclass-superclass:%@======metaClass-superclass-superclass-superclass_class_isMetaClass:%d",[[[animalMetaCls superclass]superclass]superclass],class_isMetaClass([[[animalMetaCls superclass]superclass]superclass]));

    NSLog(@"metaClass-superclass-superclass-superclass-superclass:%@======metaClass-superclass-superclasss-superclass-superclass_class_isMetaClass:%d",[[[[animalMetaCls superclass]superclass]superclass]superclass],class_isMetaClass([[[[animalMetaCls superclass]superclass]superclass]superclass]));

    NSLog(@"metaClass-superclass-superclass-superclass-superclass-superclass:%@======metaClass-superclass-superclass-superclasss-superclass-superclass_class_isMetaClass:%d",[[[[[animalMetaCls superclass]superclass]superclass]superclass] superclass],class_isMetaClass([[[[[animalMetaCls superclass]superclass]superclass]superclass] superclass]));

    

    NSLog(@"metaClass-superclass-superclass-superclass-superclass-superclass-superclass:%@======metaClass-superclass-superclass--superclass-superclasss-superclass-superclass_class_isMetaClass:%d",[[[[[[animalMetaCls superclass]superclass]superclass]superclass] superclass] superclass],class_isMetaClass([[[[[[animalMetaCls superclass]superclass]superclass]superclass] superclass] superclass]));

}
 


int main(int argc, const char * argv[]) {

    @autoreleasepool {

        test11();

    }

    return 0;

}
 Copy code 

image.png

  • instance Of isa Point to class
    • When an object method is called , adopt instance Of isa find class, Finally, find the implementation of the object method to call
  • class Of isa Point to meta-class
    • When calling a class method , adopt class Of isa find meta-class, Finally, find the implementation of the class method to call
  • meta-class Of isa Pointing to the base class meta-class
  • The base class isa Point to your

2.superclass The pointer

Through the previous Introduction , We learned that : Class object for each class 、 Metaclass objects have a superclass The pointer

  • class Of superclass Pointer to the parent class class
    • If there is no parent class ,superclass Pointer for nil
  • meta-class Of superclass Pointing to the parent class meta-class
    • The base class meta-class Of superclass Pointing to the base class class

3. Method call | Addressing

instance The path of calling object methods

  • isa find class, Method does not exist , Just through superclass Find parent

class Call the trace of class method

  • isa look for meta-class, Method does not exist , Just through superclass Find parent

4. prove isa The pointer points to the above conclusion ?

We prove through the following code :

NSObject *object = [[NSObject alloc] init];
Class objectClass = [NSObject class];
Class objectMetaClass = object_getClass([NSObject class]);
        
NSLog(@"%p %p %p", object, objectClass, objectMetaClass);
 
 Copy code 

Break the point and print the corresponding object through the console isa The pointer

 Print object Of isa Pointers and objectClass The address of

We found that object->isa And objectClass The address of is different , This is because from 64bit Start ,isa A bit operation is required , To calculate the real address . The value of bit operation can be downloaded objc Source code find .

ISA_MASK

We verify it by bit operation .

isa Calculate the correct address through bit operation

We found that ,object-isa Pointer address 0x001dffff96537141 After the same 0x00007ffffffffff8 An operation , obtain objectClass The address of 0x00007fff96537140

Then let's verify class Object's isa Whether the pointer also needs bit operation to calculate meta-class Address of the object . When we print in the same way objectClass->isa When the pointer , Found unable to print

p/x objectClass->isa

Also found on the left objectClass There's No... in the object isa The pointer . We are here Class Take a look inside

typedef struct objc_class *Class;

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

 Copy code 

I believe I know about isa The students of the pointer are right objc_class The contents of the structure are familiar , There is no in-depth study here today , We only look at the first object is a isa The pointer , In order to get isa The address of the pointer , We create the same structure and get it through forced transformation isa The pointer .

struct hp_objc_class{
    Class isa;
};


Class objectClass = [NSObject class];
struct hp_objc_class *objectClass2 = (__bridge struct hp_objc_class *)(objectClass);

 Copy code 

At this point, let's re verify

objectClass2->isa

exactly ,objectClass2 Of isa The address of the pointer after bit operation is meta-class The address of .

5、 ... and 、 Further exploration Class The underlying structure of the object

1.Class The essence of

We know that whether it's class objects or metaclass objects , Types are Class,class and mete-class The bottom floor is objc_class Pointer to structure , In memory is the structure , This chapter explores Class The essence of .

Class objectClass = [NSObject class];        
Class objectMetaClass = object_getClass([NSObject class]);
 
 Copy code 

Click on Class Come inside , We can find out

typedef struct objc_class *Class;
 Copy code 

Class Object is actually a point to objc_class Pointer to structure . Therefore, we can say that class objects or metaclass objects in memory are actually objc_class Structure .

We are here objc_class Inside , You can see the code that often appears in the underlying principles .

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
 
 Copy code 

I believe this part of the code is very common in this article , however OBJC2_UNAVAILABLE; The code is no longer in use . So far objc_class What kind of structure is it ? We go through objc Source code to find objc_class Content of structure .

 part objc_class Code content

We found that this structure inherits objc_object And there are some functions in the structure , Because this is c++ Structure , stay c I've expanded on , Therefore, the structure can contain functions . We are here objc_object Inside , Intercept part of the code

objc_object Internal sub code

We found that objc_object There is one of them. isa The pointer , that objc_class Inherit objc_object, Also have a isa The pointer

So what we learned before , The member variable information of the class stored in the class , Example method , Where are the attribute names and other information . We are here class_rw_t in , Intercept part of the code , We found that class_rw_t A list of methods is stored in the , Property list , Agreement list, etc .

class_rw_t Part of the code

and class_rw_t It's through bits call data It's got to be , We are here data Method internal implementation . We can see ,data Inside the function, it's just bits Conduct &FAST_DATA_MASK operation

image.png

image.png

The member variable information is stored in class_ro_t Inside , We are here class_ro_t In view .

class_ro_t Internal code

Finally, the summary is carried out through a figure

image.png

2. Prove whether the above conclusion drawn by reading the source code is correct .

Because the bottom part API Cannot be used directly in the project , And we read Apple's official open source underlying code , So we can imitate the bottom implementation of official open source , In their own projects Custom structure imitation Class The underlying implementation of .
If we write our own structure and objc_class The real structure is the same , So when we force transformation , Will be assigned one by one . Then we can get the information inside the structure .

2.1 Custom structure , Imitate Apple official class Underlying implementation

The following code is our imitation objc_class Structure , Extract the information that needs to be used , A custom structure : ( Be careful , To put .m The document was changed to .mm, Because the implementation of this code belongs to c++ The grammar of )

#import <Foundation/Foundation.h>

#ifndef HPClassInfo_h
#define HPClassInfo_h

# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# endif

#if __LP64__
typedef uint32_t mask_t;
#else
typedef uint16_t mask_t;
#endif
typedef uintptr_t cache_key_t;

struct bucket_t {
    cache_key_t _key;
    IMP _imp;
};

struct cache_t {
    bucket_t *_buckets;
    mask_t _mask;
    mask_t _occupied;
};

struct entsize_list_tt {
    uint32_t entsizeAndFlags;
    uint32_t count;
};

struct method_t {
    SEL name;
    const char *types;
    IMP imp;
};

struct method_list_t : entsize_list_tt {
    method_t first;
};

struct ivar_t {
    int32_t *offset;
    const char *name;
    const char *type;
    uint32_t alignment_raw;
    uint32_t size;
};

struct ivar_list_t : entsize_list_tt {
    ivar_t first;
};

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

struct property_list_t : entsize_list_tt {
    property_t first;
};

struct chained_property_list {
    chained_property_list *next;
    uint32_t count;
    property_t list[0];
};

typedef uintptr_t protocol_ref_t;
struct protocol_list_t {
    uintptr_t count;
    protocol_ref_t list[0];
};

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;  // instance Memory space occupied by object 
#ifdef __LP64__
    uint32_t reserved;
#endif
    const uint8_t * ivarLayout;
    const char * name;  //  Class name 
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;  //  List of member variables 
    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
};

struct class_rw_t {
    uint32_t flags;
    uint32_t version;
    const class_ro_t *ro;
    method_list_t * methods;    //  Method list 
    property_list_t *properties;    //  Property list 
    const protocol_list_t * protocols;  //  List of agreements 
    Class firstSubclass;
    Class nextSiblingClass;
    char *demangledName;
};

#define FAST_DATA_MASK 0x00007ffffffffff8UL
struct class_data_bits_t {
    uintptr_t bits;
public:
    class_rw_t* data() { //  Provide data() methods  & FAST_DATA_MASK  operation 
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }
};

/* OC object  */
struct hp_objc_object {
    void *isa;
};

/*  Class object  */
struct hp_objc_class : hp_objc_object {
    Class superclass;
    cache_t cache;
    class_data_bits_t bits;
public:
    class_rw_t* data() {
        return bits.data();
    }
    
    hp_objc_class* metaClass() { //  Provide metaClass function , Get metaclass object 
//  As we explained earlier ,isa The pointer needs to pass through once  & ISA_MASK After the operation, you can get the real address 
        return (hp_objc_class *)((long long)isa & ISA_MASK);
    }
};

#endif /* HPClassInfo_h */
 
 Copy code 

2.2 Add several classes , Used for manufacturing validation data

Next, we forcibly convert our defined classes into our customized concise class Type of structure .

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "HPClassInfo.h"

/* Person */
@interface Person : NSObject <NSCopying>
{
    @public
    int _age;
}
@property (nonatomic, assign) int height;
- (void)personMethod;
+ (void)personClassMethod;
@end

@implementation Person
- (void)personMethod {}
+ (void)personClassMethod {}
@end

/* Student */
@interface Student : Person <NSCoding>
{
    @public
    int _no;
}

@property (nonatomic, assign) int score;
- (void)studentMethod;
+ (void)studentClassMethod;
@end

@implementation Student
- (void)studentMethod {}
+ (void)studentClassMethod {}
@end int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSObject *object = [[NSObject alloc] init];
        Person *person = [[Person alloc] init];
        Student *student = [[Student alloc] init];
        
        hp_objc_class *objectClass = (__bridge hp_objc_class *)[object class];
        hp_objc_class *personClass = (__bridge hp_objc_class *)[person class];
        hp_objc_class *studentClass = (__bridge hp_objc_class *)[student class];
        
        hp_objc_class *objectMetaClass = objectClass->metaClass();
        hp_objc_class *personMetaClass = personClass->metaClass();
        hp_objc_class *studentMetaClass = studentClass->metaClass();
        
        class_rw_t *objectClassData = objectClass->data();
        class_rw_t *personClassData = personClass->data();
        class_rw_t *studentClassData = studentClass->data();
        
        class_rw_t *objectMetaClassData = objectMetaClass->data();
        class_rw_t *personMetaClassData = personMetaClass->data();
        class_rw_t *studentMetaClassData = studentMetaClass->data();

        // 0x00007ffffffffff8
        NSLog(@"%p %p %p %p %p %p",  objectClassData, personClassData, studentClassData,
              objectMetaClassData, personMetaClassData, studentMetaClassData);

    return 0;
} 
 Copy code 

2.3 Interrupt to verify

By interrupting , We can see class Internal information .

thus , Let's take out the classic picture again , In the analysis diagram one by one isa Pointers and superclass Pointer pointing

isa、superclass Directional graph

2.4 instance object

First let's look at instance object , Through the previous introduction, it is not difficult for us to know :

  • instance object There is a store of isa Pointers and other member variables ,
  • instance object Of isa The pointer is pointing to its Class object Address of the

Let's first analyze the... We created in the above code :

  • object,person,student Three instance object
  • Its corresponding class object objectClass,personClass,studentClass.

instance Object analysis

From the picture above, we can see that :

    1. instance object It does store isa Pointer and its member variables
    1. take instance Object's isa The pointer after & operation The calculated address is indeed its The memory address of the corresponding class object
    1. Thus we prove isa,superclass Point to... In the graph 1,2,3 Line no. .

2.5 class object

Then let's see class object , Also through the previous Introduction , We know clearly :

  • class object There is a store of :
    • isa The pointer ,
    • superclass The pointer
    • Property information of class , Class member variable information , Object method of class , and Class
  • And by facing object Source code analysis , We know above Information stored in class Object's class_rw_t in

We spy on the content through forced transformation . Here's the picture

personClassData Inner structure

  • In the figure above, we simulate person Class object call .data function :
      1. to bits Conduct &FAST_DATA_MASK(0x00007ffffffffff8UL) operation
      1. And into class_rw_t. That is, in the figure above personClassData.
  • Among them we found Member variable information , Object methods , Properties and other information Display only first first
    • If you want to get more, you need to move the pointer back through the code to get .
  • In the picture above instaceSize = 16 Same as person In the object isa The pointer 8 Bytes +_age4 Bytes +_height4 A byte corresponds to .( There's no expansion here, right objectClassData And studentClassData Analyze , The basic content is the same as personClassData identical .)

So... In class objects isa Pointers and superclass Is the pointer pointing like the classic diagram ? So let's verify that .

 Class object isa Pointers and superclass Pointer to

Through the analysis of the memory address in the figure above , Thus we prove that :

  • isa,superclass Point to... In the diagram ,isa Pointer 4,5,6 Line no.
  • as well as superclass Pointer 10,11,12 Line no.

2.6 meta-class object

Finally, let's look at meta-class Metaclass object
As mentioned in the previous section meta-class in It stores :

  • isa The pointer
  • superclass The pointer
  • Class method information .
  • At the same time, we know meta-class Metaclass object And class Class object , Same structure , It's just that the information stored is different .
  • also Of metaclass objects isa The pointer Point to Metaclass object of base class ,
  • The metaclass object of the base class isa The pointer Point to own
  • Of metaclass objects superclass The pointer Point to The metaclass object of its parent class
  • The metaclass object of the base class superclass The pointer Point to its class object .

And class The objects are the same , We also simulate person Metaclass object calls .data function , to bits Conduct &FAST_DATA_MASK(0x00007ffffffffff8UL) operation , And into class_rw_t.

personMetaClassData Inner structure

First of all, we can see that the structure is the same as personClassData identical , And the information such as member variables and attribute list is empty , and methods Class methods are stored in personClassMethod.

Next, let's verify isa And superclass Whether the pointer points to the same serial number as the above figure .

meta-class Of isa Pointer to

The address in the figure above proves that meta-class Of isa Pointing to the base class meta-class, The base class isa The pointer also points to itself .

meta-class Of superclass Pointer to

The address in the figure above proves that meta-class Of superclass Pointing to the parent class meta-class, The base class meta-class Of superclass Pointing to the base class class class .

summary

The whole length of this article It introduces OC In object-oriented syntax Several objects (【 Instance object 、 Class object 、 The metaclass 】)、 Object's isa The pointer 、superclass、 Object 、 as well as Class And verify the understanding and inference of reading the source code . This article only reads or verifies the underlying code related to the subject , Not spread out to introduce . This article concludes , Other key points related to the underlying principles , It will be known next time

Feature series

1. Pre knowledge

2. be based on OC Language exploration iOS Underlying principle

3. be based on Swift Language exploration iOS Underlying principle

Other topics on underlying principles

1. Topics related to underlying principles

2.iOS Related topics

3.webApp Related topics

4. Topics related to cross platform development solutions

5. A staged summary :Native、WebApp、 Performance comparison of three cross platform development schemes

6.Android、HarmonyOS Page rendering theme

7. Applet page rendering theme

1. Topics related to underlying principles

2.iOS Related topics

3.webApp Related topics

4. Topics related to cross platform development solutions

5. A staged summary :Native、WebApp、 Performance comparison of three cross platform development schemes

6.Android、HarmonyOS Page rendering theme

7. Applet page rendering theme

copyright notice
author[Zhang without a story],Please bring the original link to reprint, thank you.
https://en.cdmana.com/2022/135/202205111329430088.html

Random recommended