This is the third day of my participation in Gwen Challenge
preface
First of all, I will talk about the relationship between class and object. Class and object are the collective names of two kinds of computer languages based on computers. Objects are abstractions of objective things, and classes are abstractions of objects. A class is an abstract data type. Simply put, a class is a defined type, and an object is something that comes out of new or alloc&init. So what is an object in Objective-C and how do you implement it? As we all know, Objective-C evolved from C++, so it’s not hard to guess that there are only two C++ classes or constructs that can be implemented. Now let’s use Clang to see how classes are implemented in Objective-C.
Implementation of OC objects
For convenience, I created a new MacOS command-line project and changed my main.m to main.mm to compare C++ and Objective-C classes.
Main. mm file code:
#import <Foundation/Foundation.h> class LQPeople { private: int a; protected: int b`; ` public: int c; }; @interface LQTest : NSObject @property(nonatomic,copy)NSString *name; @end int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!" ); } return 0; }Copy the code
Use the clang command
clang -rewrite-objc main.mm -o main.cpp
Get our mian. CPP file and open the CPP file to search our LQTest.
foundLQTest
It’s one of the two hypotheses, it’s the structure, but there’s something vaguely wrong with ourname
Go to which? Turned out to beLQTest
Has not been realized…
One more time…
Main. mm file code:
#import <Foundation/Foundation.h> class LQPeople { private: int a; protected: int b; public: int c; }; @interface LQTest : NSObject @property(nonatomic,copy)NSString *name; @end @implementation LQTest @end int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!" ); } return 0; }Copy the code
Use the clang command
clang -rewrite-objc main.mm -o main.cpp
Get our mian. CPP file and open CPP to view it.
There you go. OurLQTest
It turns into a structure and comes to a conclusionOC classes are struct implementations, and the objects we create are actually structures.
summary
- OC classes are struct implementations, and the objects we create are actually structures.
- The OC class is not implemented and only generates a structure identifier.
The nature of OC objects
Now that we know that OC objects are essentially structures, let’s explore how objects are implemented. What is the nature of the object? What does the property become? What’s the method going to be?
attribute
Code first:
@interface LQTest : NSObject @property(nonatomic,assign)int i; @property(nonatomic,assign)char c; @property(nonatomic,assign)bool b; @property(nonatomic,strong)NSString *name; @property(nonatomic,strong)NSData *data; @property(nonatomic,strong)NSDate *date; @end @implementation LQTest -(void)test { } @end int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!" ); } return 0; }Copy the code
Use the clang command
clang -rewrite-objc main.mm -o main.cpp
Get our mian. CPP file and open it up.
Class isa pointer to objc_class. When I tried to find objc_class, I found only one definition. The implementation is not there. I won’t go into this for the time being, but I’ll study it later.
struct NSObject_IMPL {
Class isa;
};
typedef struct objc_class *Class;
Copy the code
The underlying member variables still hold char, bool, int. But NSString, NSData, and NSDate are not NSString, NSData, and NSDate in our OC. It’s all structure objc_Object. Objc_object has only one isa pointer of Class type in it.
// @class NSString;
#ifndef _REWRITER_typedef_NSString
#define _REWRITER_typedef_NSString
typedef struct objc_object NSString;
typedef struct {} _objc_exc_NSString;
#endif
// @class NSData;
#ifndef _REWRITER_typedef_NSData
#define _REWRITER_typedef_NSData
typedef struct objc_object NSData;
typedef struct {} _objc_exc_NSData;
#endif
// @class NSDate;
#ifndef _REWRITER_typedef_NSDate
#define _REWRITER_typedef_NSDate
typedef struct objc_object NSDate;
typedef struct {} _objc_exc_NSDate;
#endif
struct objc_object {
Class _Nonnull isa __attribute__((deprecated));
};
Copy the code
methods
We don’t see the method we defined in the structure definition. Where did the defined methods go? Let’s keep looking.
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[25];
} _OBJC_$_INSTANCE_METHODS_LQTest __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
25,
{{(struct objc_selector *)"test", "v16@0:8", (void *)_I_LQTest_test},
{(struct objc_selector *)"i", "i16@0:8", (void *)_I_LQTest_i},
{(struct objc_selector *)"setI:", "v20@0:8i16", (void *)_I_LQTest_setI_},
{(struct objc_selector *)"c", "c16@0:8", (void *)_I_LQTest_c},
{(struct objc_selector *)"setC:", "v20@0:8c16", (void *)_I_LQTest_setC_},
{(struct objc_selector *)"b", "B16@0:8", (void *)_I_LQTest_b},
{(struct objc_selector *)"setB:", "v20@0:8B16", (void *)_I_LQTest_setB_},
{(struct objc_selector *)"name", "@16@0:8", (void *)_I_LQTest_name},
{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_LQTest_setName_},
{(struct objc_selector *)"data", "@16@0:8", (void *)_I_LQTest_data},
{(struct objc_selector *)"setData:", "v24@0:8@16", (void *)_I_LQTest_setData_},
{(struct objc_selector *)"date", "@16@0:8", (void *)_I_LQTest_date},
{(struct objc_selector *)"setDate:", "v24@0:8@16", (void *)_I_LQTest_setDate_},
{(struct objc_selector *)"i", "i16@0:8", (void *)_I_LQTest_i},
{(struct objc_selector *)"setI:", "v20@0:8i16", (void *)_I_LQTest_setI_},
{(struct objc_selector *)"c", "c16@0:8", (void *)_I_LQTest_c},
{(struct objc_selector *)"setC:", "v20@0:8c16", (void *)_I_LQTest_setC_},
{(struct objc_selector *)"b", "B16@0:8", (void *)_I_LQTest_b},
{(struct objc_selector *)"setB:", "v20@0:8B16", (void *)_I_LQTest_setB_},
{(struct objc_selector *)"name", "@16@0:8", (void *)_I_LQTest_name},
{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_LQTest_setName_},
{(struct objc_selector *)"data", "@16@0:8", (void *)_I_LQTest_data},
{(struct objc_selector *)"setData:", "v24@0:8@16", (void *)_I_LQTest_setData_},
{(struct objc_selector *)"date", "@16@0:8", (void *)_I_LQTest_date},
{(struct objc_selector *)"setDate:", "v24@0:8@16", (void *)_I_LQTest_setDate_}}
};
// @implementation LQTest
static void _I_LQTest_test(LQTest * self, SEL _cmd) {
}
static int _I_LQTest_i(LQTest * self, SEL _cmd) { return (*(int *)((char *)self + OBJC_IVAR_$_LQTest$_i)); }
static void _I_LQTest_setI_(LQTest * self, SEL _cmd, int i) { (*(int *)((char *)self + OBJC_IVAR_$_LQTest$_i)) = i; }
static char _I_LQTest_c(LQTest * self, SEL _cmd) { return (*(char *)((char *)self + OBJC_IVAR_$_LQTest$_c)); }
static void _I_LQTest_setC_(LQTest * self, SEL _cmd, char c) { (*(char *)((char *)self + OBJC_IVAR_$_LQTest$_c)) = c; }
static bool _I_LQTest_b(LQTest * self, SEL _cmd) { return (*(bool *)((char *)self + OBJC_IVAR_$_LQTest$_b)); }
static void _I_LQTest_setB_(LQTest * self, SEL _cmd, bool b) { (*(bool *)((char *)self + OBJC_IVAR_$_LQTest$_b)) = b; }
static NSString * _I_LQTest_name(LQTest * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LQTest$_name)); }
static void _I_LQTest_setName_(LQTest * self, SEL _cmd, NSString *name) { (*(NSString **)((char *)self + OBJC_IVAR_$_LQTest$_name)) = name; }
static NSData * _I_LQTest_data(LQTest * self, SEL _cmd) { return (*(NSData **)((char *)self + OBJC_IVAR_$_LQTest$_data)); }
static void _I_LQTest_setData_(LQTest * self, SEL _cmd, NSData *data) { (*(NSData **)((char *)self + OBJC_IVAR_$_LQTest$_data)) = data; }
static NSDate * _I_LQTest_date(LQTest * self, SEL _cmd) { return (*(NSDate **)((char *)self + OBJC_IVAR_$_LQTest$_date)); }
static void _I_LQTest_setDate_(LQTest * self, SEL _cmd, NSDate *date) { (*(NSDate **)((char *)self + OBJC_IVAR_$_LQTest$_date)) = date; }
// @end
Copy the code
We can see that our methods have all become static c++ functions, with an _method_list_t to map them.