[0] outline
-- [1] version and Platform
-- [2] interaction with runtime system
-- [3] dynamic resolution of methods
-- [4] Message forwarding
-- [5] type Encoding
-- [6] attribute Declaration
[1] versions and platforms
For objective-C, the runtime system is like an operating system or a running support platform. It enables objective-C code to run according to the established language features. Compared with C/C ++, objective-C tries its best to postpone some actions to the runtime for execution, that is, to do things dynamically as much as possible. Therefore, it requires not only a compiler, but also a runtime environment to execute the compiled code.
Runtime system is divided into two versions: Legacy and Modern. Generally, we use the modern version. A notable feature of the runtime system of the modern version is "non-fragile", that is, when the layout of the member variables of the parent class changes, the subclass does not need to be re-compiled. In addition, it supports merging declared attributes (that is@ PropertyAnd@ Synthesis).
The following describes how nsobject and objective-C Programs interact with the runtime system, dynamically load classes during runtime, send messages to other objects, and obtain object information during runtime.
[2] interacting with the runtime system
The objective-C program interacts with the runtime system at three different levels: Through the objective-C source code, functions defined through nsobject, and by directly calling runtime functions.
Generally, the runtime system works behind the scenes. What we need to do is to write objective-C code and then compile it. The compiler will create corresponding data structures and function calls for us to realize the dynamic characteristics of the language. These data structures store information that can be found in the class, category definition, and Protocol declaration, including the member variable template, selectors, and other information extracted from the source code.
Runtime system is a dynamic shared library located in/Usr/include/objc, Has a set of public interfaces, composed of a series of functions and data structures. Developers can use pure C to call some functions for Compiler operations, or expand the runtime system to create tools for the development environment. Although objective-C does not need to be understood in general, it is sometimes useful. All functions have documented information in objective-C Runtime reference.
In cocoa, most objects are nsobject subclasses (nsproxy is an exception) and inherit the nsobject method. Therefore, in this inheritance system, sub-classes can re-implement nsobject-defined functions as needed to achieve polymorphism and dynamics, suchDescriptionMethod (returns a string that describes itself, similar to the three quotation marks in Python ).
Some nsobject-defined methods simply ask the runtime system to obtain information, so that the object can be introspective (introspection), for example, iskindofclass used to determine the class type :, determine the ismemberofclass of the object in the inheritance system:, determine whether an object can receive a specific message respondstoselector:, and determine whether an object complies with the conformstoprotocol of a certain protocol :, and methodforselector that provides the method implementation address :. These methods allow an object to perform introspection (Introspect about itself).
The main runtime function is used to send messages. It is triggered by the message expression in the source code. Message sending is the most common expression in objective-C Programs, which is eventually converted to the objc_msgsend function call. For example, a message expression [Receiver message] is convertedObjc_msgsend (generator er, selector)If there is a parameter, it isObjc_msgsend (separator er, selector, arg1, arg2 ,...).
Messages are bound to function implementation only when they are running: firstObjc_msgsendFind the function implementation corresponding to the selector in the generator er. Call the function process to pass the processing ing object (that is, the this pointer) and parameters to the previous one. Finally, return the return value of the function.
The key to message sending isThe structure created by the compiler for classes and objectsContains two main elements: one is the pointer to superclass, and the other is the dispatch table of the class.Selector and corresponding function entry address Association.
When an object is created, the first element in the memory layout is a pointer to the class structure, Isa. Using the ISA pointer, an object can access its class structure and then access the inherited class structure. SeeHere.
When sending a message to an object, objc_msgsend first searches for the function entry address of the selector in the dispatch table of the class through the ISA pointer. If no message is found, it is searched along the class hierarchy (class inheritance system) until the nsobject class. This is to select function implementation during runtime. In the OOP line, it is dynamic binding.
To speed up message sending, runtime system createsCacheUsed to cache the selecing between selector and the corresponding function entry address.
When objc_msgsend finds the corresponding function implementation, in addition to passing function parameters, it also passes two hidden parameters:Processing objectAndSelector. These two parameters are called hidden parameters because they are not declared in the source code, but can still be accessed through self and _ cmd.
When a message is sent to an object many times, you can directly use methodforselector for optimization, such as the following code:
[CPP]View plaincopy
- //////////////////////////////////////// //////////////////////
- Void (* setter) (ID, Sel, bool );
- Int I;
- Setter = (void (*) (ID, Sel, bool) [target
- Methodforselector: @ selector (setfilled :)];
- For (I = 0; I <1000, I ++)
- Setter (targetlist [I], @ selector (setfilled :), yes );
- //////////////////////////////////////// //////////////////////
Among them, methodforselector: Provided by cocoa runtime system, rather than objective-c's own language features. Note the correctness of the function type during the conversion process, including the return value and parameters. The first two parameters must be declared as ID and SEL.
[3] dynamic method resolution
Sometimes we want to provide dynamic implementation for a method, such as objective-C's@ DynamicIt tells the compiler that the method corresponding to the attribute is provided dynamically. We can use resolveinstancemethod: And resolveclassmethod: to provide dynamic implementation for object methods and class methods respectively.
An objective-C method is essentially a C function with at least two parameters (self and _ cmd). We can use class_addmethod to add a method to a class. For example, for the following functions:
[CPP]View plaincopy
- //////////////////////////////////////// //////////////////////
- Void dynamicmethodimp (ID self, Sel _ cmd ){
- // Implementation ....
- }
- //////////////////////////////////////// //////////////////////
We can use resolveinstancemethod to add it as a method (for exampleResolvethismethoddynamically):
[CPP]View plaincopy
- //////////////////////////////////////// //////////////////////
- @ Implementation myclass
- + (Bool) resolveinstancemethod :( SEL) Asel
- {
- If (Asel = @ selector (resolvethismethoddynamically )){
- Class_addmethod ([self class], Asel, (IMP) dynamicmethodimp, "[email protected]:");
- Return yes;
- }
- Return [Super resolveinstancemethod: Asel];
- }
- @ End
- //////////////////////////////////////// //////////////////////
Dynamic resolution does not conflict with message sending. Before the message mechanism takes effect, a class has the opportunity to dynamically decide a method. When respondstoselector: Or instancesrespondtoselector: is activated, dynamic method resolver will give priority to the opportunity to provide an implementation for this selector. If resolveinstancemethod is implemented: For selectors that do not want to dynamically decide but want them to follow the message forwarding mechanism, return no.
The objective-C program can link new classes and category at runtime. Dynamic Loading can be used to do many different things. For example, various modules in system preferences are dynamically loaded. Although runtime functions can dynamically load the objective-C Module (objc_loadmodules in the objc/objc-load.h), cocoa's nsbundle class provides a more convenient dynamic loading interface.
[4] Message forwarding
A message sent to an object that is not processed is an error. However, before an error is reported, the runtime system gives the recipient a second chance to process the message. In this case, the runtime system sends a message to the object, forwardinvocation:. The message only carries one nsinvocation object as the parameter-This nsinvocation object encapsulates the original message and corresponding parameters.
By implementing forwardinvocation: The method (inherited from nsobject), you can provide a default processing method for non-responding messages. Like the method name, the common processing method is to forward the message to another object:
[CPP]View plaincopy
- //////////////////////////////////////// //////////////////////
- -(Void) forwardinvocation :( nsinvocation *) aninvocation
- {
- If ([someotherobject respondstoselector: [aninvocation selector])
- [Aninvocation invokewithtarget: someotherobject];
- Else
- [Super forwardinvocation: aninvocation];
- }
- //////////////////////////////////////// //////////////////////
For unrecognized messages (not found in the dispatch table), forwardinvocation is like a transfer station. Developers decide whether to continue shipping or stop not to process messages.
[5] type Encoding
To support runtime system, the compiler encodes the return value type and parameter type. The corresponding compiler indicator is@ Encode.
For example, the void encoding is V, the char encoding is C, the object encoding is @, the class encoding is #, And the selector encoding is:, and the conformity type is composed of basic types, such
[CPP]View plaincopy
- Typedef struct example {
- Id anobject;
- Char * astring;
- Int anint;
- } Example;
Encoded as {[email protected] * I }.
[6] attribute Declaration
When the compiler encounters an attribute declaration, it will generate some descriptive metadata (metadata) and associate it with the corresponding class, category and protocol. Some functions can search for these metadata by name in the class or Protocol. Through these functions, we can obtain the encoded attribute type (string ), copy the attribute list (C string array) of the attribute ). Therefore, we can obtain the attribute list of each class and protocol.
Similar to type encoding, attribute types also have corresponding encoding schemes, such as readonly encoding is R, copy encoding is C, and retain encoding is.
You can use the property_getattributes function to encode a string that starts with T, followed by @ encode type and comma, and ends with V and variable name. For example:
[CPP]View plaincopy
- @ Property char chardefault;
Description:TC, vchardefault
[CPP]View plaincopy
- @ Property (retain) ididretain;
Description:[Email protected], &, vidretain
The property struct defines an opaque handle pointing to the property descriptor:Typedef struct objc_property * property;.
You can use the class_copypropertylist and protocol_copypropertylist functions to obtain the corresponding attribute array:
[CPP]View plaincopy
- Objc_property_t * class_copypropertylist (class CLs, unsigned int * outcount)
- Objc_property_t * protocol_copypropertylist (Protocol * proto, unsigned int * outcount)
The property_getname function can be used to obtain the attribute name.
You can use class_getproperty and protocol_getproperty to obtain the Property Reference Based on the given name:
[CPP]View plaincopy
- Objc_property_t class_getproperty (class CLs, const char * name)
- Objc_property_t protocol_getproperty (Protocol * proto, const char * Name, bool isrequiredproperty, bool isinstanceproperty)
You can use the property_getattributes function to obtain the @ encode type string of the attribute:
Const char * property_getattributes (objc_property_t Property)
The above functions are combined into a sample code:
[CPP]View plaincopy
- @ Interface lender: nsobject {
- Float alone;
- }
- @ Property float alone;
- @ End
- Id lenderclass = objc_getclass ("lender ");
- Unsigned int outcount, I;
- Objc_property_t * properties = class_copypropertylist (lenderclass, & outcount );
- For (I = 0; I <outcount; I ++ ){
- Objc_property_t property = properties [I];
- Fprintf (stdout, "% S % s \ n", property_getname (property), property_getattributes (property ));
- }
Reprinted from: http://blog.csdn.net/jasonblog/article/details/7246822