OC can be compiled into C++ to explore the nature of classes and objects from a C++ perspective

1. Convert OC files into C++ files

Generate the following.m file with _2415 as an identifier

#import <Foundation/Foundation.h>
@interface Persion_2415 : NSObject
@property(nonatomic, copy) NSString * name_2415;
@property(nonatomic, assign) int age_2415;
-(int) doWork_2415:(int) week;
@end
@implementation Persion_2415
-(int) age_2415{
    return self.age_2415;
}
-(int) doWork_2415:(int) week {
    return 39990;
}
+(int) clDoWork_2415:(int) week {
    return 500000;
}
@end


@interface Student_2415 : Persion_2415
@property(nonatomic, copy) NSString * school_2415;
@end

@implementation Student_2415
@end


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Persion_2415 * persion_2415 = [[Persion_2415 alloc] init];
        
        NSLog(@"%@",persion_2415);
    }
    return 0;
}


Copy the code

Generate C++ files from OC files

  • clang -rewrite-objc main.m -o main.cpp

2. Explore main.cpp

Look for Persion_2415 in main.cpp

#ifndef _REWRITER_typedef_Persion_2415
#define _REWRITER_typedef_Persion_2415
typedef struct objc_object Persion_2415;   // Persion_2415 is a struct objc_object structure
typedef struct {} _objc_exc_Persion_2415;
#endif

extern "C" unsigned long OBJC_IVAR_$_Persion_2415$_name_2415;
extern "C" unsigned long OBJC_IVAR_$_Persion_2415$_age_2415;
struct Persion_2415_IMPL {                 // The data stored in Persion is a struct Persion_2415_IMPL
	struct NSObject_IMPL NSObject_IVARS;
	int _age_2415;
	NSString *_name_2415;
};

Copy the code

Struct objc_object {struct objc_object

typedef struct objc_class *Class;     //Class is struct objc_class *

struct objc_object {                  / / struct objc_object definition
    Class _Nonnull isa __attribute__((deprecated));
};																		

typedef struct objc_object *id;       // Define the id

typedef struct objc_selector *SEL;    The definition of / / SEL
Copy the code

Id, SEL, Class are all structure Pointers, and so are objects. For example, persion is written in OC as persion * persion = struct objc_object * persion, which is the same definition as ID. So id can represent all objects

Struct objc_class {struct objc_class = struct objc_class

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;																		//isa

#if! __OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;   / / parent class
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;		/ / name
    long version                                             OBJC2_UNAVAILABLE;		/ / version
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;		/ / size
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;		// Member list
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;																																 // List of methods
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;		/ / cache
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;   // Protocol list
#endif

} OBJC2_UNAVAILABLE;
Copy the code

Struct objc_selector {struct objc_selector

Struct Persion_2415_IMPL (struct objc_object, struct Persion_2415_IMPL, struct objc_object, struct Persion_2415_IMPL

Search the doWork_2415 method and find:

static int _I_Persion_2415_doWork_2415_(Persion_2415 * self, SEL _cmd, int week) {
    return 39990;
}
static int _C_Persion_2415_clDoWork_2415_(Class self, SEL _cmd, int week) {
    return 500000;
}
Copy the code

The object method and class method of each class are static functions

Also found:

static struct/ * _method_list_t* / {
	unsigned int entsize;  // sizeof(struct _objc_method)
	unsigned int method_count;
	struct _objc_method method_list[8].
} _OBJC_$_INSTANCE_METHODS_Persion_2415 __attribute__ ((used, section ("__DATA,__objc_const"))) = {
	sizeof(_objc_method),
	8,
	{{(struct objc_selector *)"age_2415"."i16@0:8", (void *)_I_Persion_2415_age_2415},
	{(struct objc_selector *)"doWork_2415:"."i20@0:8i16", (void *)_I_Persion_2415_doWork_2415_},
	{(struct objc_selector *)"name_2415"."@ @ 0:8 16", (void *)_I_Persion_2415_name_2415},
	{(struct objc_selector *)"setName_2415:"."v24@0:8@16", (void *)_I_Persion_2415_setName_2415_},
	{(struct objc_selector *)"setAge_2415:"."v20@0:8i16", (void *)_I_Persion_2415_setAge_2415_},
	{(struct objc_selector *)"name_2415"."@ @ 0:8 16", (void *)_I_Persion_2415_name_2415},
	{(struct objc_selector *)"setName_2415:"."v24@0:8@16", (void *)_I_Persion_2415_setName_2415_},
	{(struct objc_selector *)"setAge_2415:"."v20@0:8i16", (void *)_I_Persion_2415_setAge_2415_}}
};
Copy the code

Struct _objc_method {struct _objc_method {struct _objc_method

struct _objc_method {
	struct objc_selector * _cmd;
	const char *method_type;
	void  *_imp;
};
Copy the code

So, what’s the rule for method_type? I found a table with a base address offset after the letter, but I don’t know how to calculate the number, but you can use method_getTypeEncoding if you want to use it

Post a sheet (quote from websiteBlog.csdn.net/mr_yong/art… )

Search for _OBJC_$_INSTANCE_METHODS_Persion_2415 to see where it is referenced and find:

static struct _class_ro_t _OBJC_CLASS_RO_The $_Persion_2415 __attribute__ ((used.section(" __DATA, __objc_const"))) = {
	0, __OFFSETOFIVAR__(struct Persion_2415, _age_2415), sizeof(struct Persion_2415_IMPL), 
	(unsigned int)0.0."Persion_2415",
	(const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_Persion_2415,
	0, 
	(const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_Persion_2415,
	0, 
	(const struct _prop_list_t *)&_OBJC_$_PROP_LIST_Persion_2415,
};
Copy the code

Struct _class_ro_t {struct _class_ro_t {

struct _class_ro_t {
	unsigned int flags;
	unsigned int instanceStart;
	unsigned int instanceSize;
	unsigned int reserved;
	const unsigned char *ivarLayout;
	const char *name;
	const struct _method_list_t *baseMethods;
	const struct _objc_protocol_list *baseProtocols;
	const struct _ivar_list_t *ivars;
	const unsigned char *weakIvarLayout;
	const struct _prop_list_t *properties;
};
Copy the code

Struct _ivar_t {, struct _protocol_t {

struct _protocol_t {
	void * isa;  // NULL
	const char *protocol_name;
	const struct _protocol_list_t * protocol_list; // super protocols
	const struct method_list_t *instance_methods;
	const struct method_list_t *class_methods;
	const struct method_list_t *optionalInstanceMethods;
	const struct method_list_t *optionalClassMethods;
	const struct _prop_list_t * properties;
	const unsigned int size;  // sizeof(struct _protocol_t)
	const unsigned int flags;  / / = 0
	const char ** extendedMethodTypes;
};

struct _ivar_t {
	unsigned long int *offset;  // pointer to ivar offset location
	const char *name;
	const char *type;
	unsigned int alignment;
	unsigned int  size;
};
Copy the code

Find where _OBJC_CLASS_RO_$_Persion_2415 is used:

extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_The $_Persion_2415 __attribute__ ((used.section(" __DATA, __objc_data"))) = {
	0.// &OBJC_METACLASS_$_Persion_2415,
	0.// &OBJC_CLASS_$_NSObject,
	0.// (void *)&_objc_empty_cache,
	0.// unused, was (void *)&_objc_empty_vtable,
	&_OBJC_CLASS_RO_$_Persion_2415,
};
Copy the code

Struct _class_t {where to find:

struct _class_t {
	struct _class_t *isa;
	struct _class_t *superclass;
	void *cache;
	void *vtable;
	struct _class_ro_t *ro;
};
Copy the code

If you look at the main function, you can see that all method calls are made through objc_msgSend

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        Persion_2415 * persion_2415 = ((Persion_2415 *(*)(id, SEL))(void *)objc_msgSend)((id)((Persion_2415 *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Persion_2415"), sel_registerName("alloc")), sel_registerName("init"));

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_2k_hpcfw7594615f89pv2ydfbmh__2sjv_T_main_c2be56_mi_0,persion_2415);
    }
    return 0;
}
Copy the code

Conclusion:

  1. Objc objects and id types are Pointers to struct objc_object * structures in C++

  2. Class member methods and class method implementations are static functions with two default arguments self, SEL _cmd

  3. Both class and object methods are called through objc_msgSend

Question:

An objC object is a pointer to a struct objc_object *, but the struct objc_object only holds class information. The object information is stored in Persion_2415_IMPL. So how is Persion_2415_IMPL associated?