The introduction
We use objects every day, but do you know what they look like underneath? Do you know what the parts of an object are? Do you know where object member variables, properties, and methods are stored? Don’t worry, let’s deconstruct the object bit by bit to understand the basic structure of the object.
Compile the OC
We all know that ObjC is a superset of C, which encapsulates C’s implementation of objects. So it means that the C/C++ language compiled out of the implementation is the essence of its implementation, we do analysis of the results of its compilation can have a certain understanding of the class, so as to open the train of thought, to its ObjC source code to view its real implementation.
Xrun compile:
Xcrun is a command line utility that comes with Xcode installed to compile code, and is a secondary wrapper to Clang. Clang is an Apple-led, LLVM-based C/C++/Objective-C compiler that is the king of the C family of compilers.
We can create a new empty project, write down an example of a class, and compile it using xcRunCompile command:
// emulator x86_64 xcrun - SDK iphonesimulator clang -arch x86_64 -rewrite-objc main.m -o main-x86_64 -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cppCopy the code
Let’s use x86_64 to see how our class is compiled
Analysis of compilation results
We search for our class in the compiled results to see what results exist
Kind of ontology
With respect to classes, we find the compilation results shown in the figure above. The results are interesting. Macro definition judgment aside, let’s take a look at this line of code
typedef struct objc_object LGPerson;
Copy the code
What does that mean? LGPerson is an alias for objc_Object. LGPerson is an object. It doesn’t even inherit from something. It’s just an objc_object structure! Then! After compilation, it declares an additional structure
struct LGPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *_myName;
NSString *_nickName;
};
// @property (nonatomic, strong) NSString *myName;
// @property (nonatomic, strong) NSString *nickName;
Copy the code
This structure LGPerson_IMPL is the actual content of our defined class, but it is bound to our class LGPerson at run time. We search LGPerson_IMPL to see the following code
static struct _class_ro_t _OBJC_CLASS_RO_The $_LGPerson __attribute__ ((used.section(" __DATA, __objc_const"))) = {
0, __OFFSETOFIVAR__(struct LGPerson, _myName), sizeof(struct LGPerson_IMPL),
(unsigned int)0.0."LGPerson",
(const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_LGPerson,
0,
(const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_LGPerson,
0,
(const struct _prop_list_t *)&_OBJC_$_PROP_LIST_LGPerson,
};
Copy the code
I won’t go into the details here, because the binding code is also compiled, and the actual underlying code is not written that way, but we’ll get to that later. For our purposes, LGPerson_IMPL can be thought of as a concrete implementation of LGPerson.
Note: There is also a macro definition in OC called typedef struct objc_object * ID, so this is why variables declared with id in OC can be assigned to any object without error. You product, you fine product → →
If we look at the composition of the compiled result, there are only three things
struct NSObject_IMPL NSObject_IVARS;
NSString *_myName;
NSString *_nickName;
Copy the code
We’ll talk about the last two in the next section. The first one first. So the first member variable is also a structure type, from the name can be inferred should be the parent of the concrete implementation, so we search for the structure has what? The search results are as follows
See this, then does that meanNSObject
Does this class have only one member variable ISA wow? Yeah, that’s right, that’s right.
So let’s expand a little bit
What would it look like if it were a subclass of LGPerson? So let’s go ahead and build a class like this
LGStudent
Compile the results
Is not involuntarily say to oneself!Well! That makes sense!
attribute
We all know that in OC, attributes are equal to member variables +set + GET (non-readonly). Let’s take a look at the final representation of the LGPerson attribute!
Member variables:
NSString *_myName;
NSString *_nickName;
Copy the code
Set, get methods:
static NSString * _I_LGPerson_myName(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_myName)); }
static void _I_LGPerson_setMyName_(LGPerson * self, SEL _cmd, NSString *myName) { (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_myName)) = myName; }
static NSString * _I_LGPerson_nickName(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_nickName)); }
static void _I_LGPerson_setNickName_(LGPerson * self, SEL _cmd, NSString *nickName) { (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_nickName)) = nickName; }
Copy the code
Isn’t it easy? Not complicated at all haha!
Why is _I_LGPerson_nickName not ‘nickName’? This involves encoding and storing the selector. We’ll talk about this later
Object methods and class methods
Object method and class method related content is more complex, we have a simple look at the results of compilation, there is a preliminary impression, after the article continues to dig! Let’s look at this implementation
Compile the results
Very intuitive, very simple! The runtime binding for the method is compiled as follows
Note: It also involves encoding and storing selectors, which is expanded later
conclusion
From the above analysis results, OC class is actually a structure, which stores its own and its parent’s member variables. Methods are bound to them at runtime, and of course there are other classes and protocols and a lot of things that I don’t show you directly, so you can try it out for yourself if you’re interested.
The point is, after compiling our analysis, we have led to objc_Object, the most important thing, which handles all of the runtime processing and operations, and we have seen isa today, which frequently brushes the face in the interview.
Then go on! Let’s move on to objc_Object.