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:
-
Objc objects and id types are Pointers to struct objc_object * structures in C++
-
Class member methods and class method implementations are static functions with two default arguments self, SEL _cmd
-
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?