Objective-C's total Runtime (1) Message Mechanism
Recently looking for a job, the Runtime in Objective-C is a frequently asked question, which is almost a must for large companies to interview. Of course, there are also some other questions that are almost required, such as RunLoop, Block, and memory management. I will introduce other questions in other articles if I have the opportunity. This article mainly introduces RunTime.
RunTime is short for RunTime. It is the mechanism of the system when it is running, the most important of which is the message mechanism. For C language, function calls determine which function to call during compilation (for details about C language function calls, refer to here ). After the compilation is complete, it is executed in sequence without any ambiguity. OC function call is used to send messages. It is a dynamic call process. During compilation, you cannot decide which function to call. (It turns out that in the compilation phase, OC can call any function. Even if this function is not implemented, no error will be reported if it has been declared. C language reports an error in the compilation phase ). The corresponding function can be called only when the function is running.
So how does OC implement dynamic calling? Next let's take a look at the OC's secret of dynamic calling by sending messages. If such a code is written in OC
[obj makeText];
Obj is an object and makeText is a function name. For such a simple call. During compilation, RunTime will convert the above Code
objc_msgSend(obj,@selector(makeText));
First, let's take a look at the object obj. In iOS, obj inherits from NSObject.
@interface NSObject
{ Class isa OBJC_ISA_AVAILABILITY;}
There is a Class isa pointer in NSObjcet. Then let's look at the Class
Typedef struct objc_class * Class; struct objc_class {Class isa; // points to metaclass Class super_class; // points to its parent Class const char * name; // Class name long version; // class version information. The default initialization value is 0. You can use the runtime functions class_setVersion and class_getVersion to modify and read long info. // some identification information, such as CLS_CLASS (0x1L) indicates that the class is a common class, including object methods and member variables; CLS_META (0x2L) indicates that the class is metaclass, including class methods; long instance_size; // instance variable size of this class (including instance variables inherited from the parent class); struct objc_ivar_list * ivars; // address used to store each member variable struct objc_method_list ** methodLists; // It is related to some flag bits of info, such as CLS_CLASS (0x1L). It stores object methods, such as CLS_META (0x2L), and struct objc_cache * cache; // pointer to the recently used method, used to improve efficiency; struct objc_protocol_list * protocols; // stores the protocols that this class complies}
As we can see, there are many things in a Class. Let me explain them one by one:
Class isa: Point to metaclass, which is a static Class. Generally, isa in an Obj object points to a common Class. This Class stores common member variables and object methods (Methods starting with "-"). The isa pointer in a common Class points to a static Class, static Class stores static type member variables and Class methods (Methods starting with "+ ).
Class super_class: points to the parent Class. If this Class is the root Class, it is NULL.
The following image describes the inheritance relationship between classes and objects:
Note: All isa pointers in metaclass point to metaclass. However, metaclass points to itself. Root metaclass is generated by inheriting the Root class. It is consistent with the root class struct, that is, the structure mentioned above. The difference is that the isa pointer of Root metaclass points to itself.
Other members in the Class will not be explained too much here. Let's take a look at it.
@ Selector (makeText): This is a SEL method selector. SEL is mainly used to quickly find the function pointer of the corresponding method through the method name (makeText), and then call its function. SEL itself is an Int type address, which stores the method name. For a class. Each method corresponds to a SEL. Therefore, there cannot be two methods with the same name in the iOS class. Even if the parameter type is different, because SEL is generated based on the method name, the same method name can only correspond to one SEL.
Next, let's take a look at how to dynamically find the corresponding method after a specific message is sent.
First, the compiler converts the Code [obj makeText]; To objc_msgSend (obj, @ selector (makeText); In the objc_msgSend function. First, find the class corresponding to obj through the isa pointer of obj. In the Class, first go to the cache and use SEL to find the corresponding function method (in the cache, the method list is stored using SEL as the key through the hash table, which can improve the function search speed ), if not. Search in methodList again. If no value is found in methodlist, search in superClass. If it can be found, add the method to the cache for the next search, and use the function pointer in the method to jump to the corresponding function for execution.