Objective-c Runtime [Reprint]

Source: Internet
Author: User
Tags throw exception

Original address:http://tech.glowing.com/cn/objective-c-runtime/

Hara Gupeng

If there is infringement, please contact me to delete

Objective-c

Objective-c extends the C language and joins the object-oriented and Smalltalk messaging mechanisms. The core of this extension is a runtime library written in C and compiled languages. It is the cornerstone of Objective-c object-oriented and dynamic mechanism.

Objective-c is a dynamic language, which means that it requires not only a compiler, but also a runtime system to dynamically create classes and objects, deliver messages, and forward them. Understanding Objective-c's Runtime mechanism can help us understand the language better, expand the language when appropriate, and address some design or technical issues in the project from a system level. To understand the Runtime, first understand its core-message passing (Messaging).

Message Delivery (Messaging)

I ' m sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea . The big idea is "messaging" –that are what the kernal[sic] of Smalltalk are all about ... The key in making great and growable systems are much more to design how it modules communicate rather than what their int Ernal properties and behaviors should be.

Alan Kay has repeatedly stressed that the core of Smalltalk is not object-oriented, object-oriented is just the lesser ideas, message delivery is the big idea.

In many languages, such as C, invoking a method is actually jumping to a point in memory and starting to execute a piece of code. There is no dynamic feature, because this is determined at compile time. In Objective-c, however, the [object foo] syntax does not immediately execute the code of the Foo method. It is a message that sends an object called Foo at run time. This message, which may be handled by object, may be forwarded to another object, or it can be ignored to pretend that the message was confiscated. Many different messages can also be implemented with the same method. These are all determined when the program is running.

In fact, the syntax of the OBJECTIVE-C function call you write at compile time will be translated into a C function call objc_msgSend() . For example, the following two lines of code are equivalent:

[Array Insertobject:foo atindex:55);

The key to messaging is hidden in objc_object the ISA pointer and objc_class in the class dispatch table.

objc_object, objc_classAnd Ojbc_method

In Objective-c, classes, objects, and methods are a struct of C, and from the objc/objc.h header file we can find their definition:

structobjc_object {Class isa objc_isa_availability;};structObjc_class {class Isa objc_isa_availability;#if!__objc2__Class Super_class; Const Char*name; Longversion; Longinfo; Longinstance_size; structObjc_ivar_list *Ivars; **structObjc_method_list **methodlists**; **structObjc_cache *cache**; structObjc_protocol_list *protocols;#endif};structObjc_method_list {structObjc_method_list *obsolete; intMethod_count;#ifdef__lp64__intspace;#endif    /*variable length structure*/    structObjc_method method_list[1];};structObjc_method {SEL method_name; Char*method_types;/*A string representing Argument/return types*/IMP Method_imp;};

objc_method_listThe essence is an objc_method array of variable lengths with elements. A objc_method struct has a function name, the SEL, a string that represents the type of the function (see Type Encoding), and the implementation of the function Imp.

From these definitions, you can see that sending a message also objc_msgSend does something. objc_msgSend(obj, foo)for this example:

    1. First, the ISA pointer of obj finds its class;
    2. Find Foo in the class method list;
    3. If the class does not reach Foo, continue to look for it in the superclass;
    4. Once the function of Foo is found, it executes its implementation imp.

But there is a problem with this implementation, which is inefficient. But a class often has only 20% of functions that are often called, which can account for 80% of the total number of calls. It is not reasonable for each message to traverse once objc_method_list . If you cache a function that is often called, it can greatly improve the efficiency of the function query. This is what objc_class another important member objc_cache does--after finding Foo, method_name save Foo as key as method_imp value. When you receive the Foo message again, you can find it directly in the cache and avoid traversing it objc_method_list .

Dynamic method parsing and forwarding

In the example above, foo what happens if you don't find it? Typically, the program hangs up at run time and throws an unrecognized selector sent to ... exception. But before the exception is thrown, the Objective-c runtime will give you three chance to save the program:

    1. Method resolution
    2. Fast forwarding
    3. Normal forwarding
Method Resolution

First, the OBJECTIVE-C runtime invokes +resolveInstanceMethod: or gives +resolveClassMethod: you the opportunity to provide a function implementation. If you add a function and return YES, the runtime restarts the message sending process. fooas an example, you can do this:

 void  Foomethod (id   obj, SEL _cmd) {NSLog ( @ " doing foo   );}  + (BOOL) Resolveinstancemethod: (SEL) asel{ if  (Asel == @selector (foo:)) {Class_addmethod ([self  class ], Asel, (IMP) Foomethod,  [email         protected]:   );     return   YES;  return   [Super Resolveinstancemethod];} 

Core Data is useful to this approach. The getter and setter of the properties in Nsmanagedobjects is dynamically added at run time.

If the Resolve method returns NO, the runtime moves to the next step: Message Forwarding (msg Forwarding).

Ps:ios 4.3 Adds a lot of new runtime methods, mostly with IMP prefixes, such as imp_implementationWithBlock() quickly creating a imp with block.
The above example can be rewritten as:

IMP fooimp = Imp_implementationwithblock (^ (ID  _self) {      NSLog (@ "Doing foo  "class"[email protected]:");  
Fast forwarding

If the target object is implemented -forwardingTargetForSelector: , Runtime calls this method, giving you the chance to forward the message to other objects.

-(ID) forwardingtargetforselector: (SEL) aselector{    if(aselector = = @selector ( Foo:) {        return  alternateobject;    }     return [Super Forwardingtargetforselector:aselector];}

As long as this method returns not nil and self, the entire message sending process is restarted and of course the sent object becomes the object you return. Otherwise, you will continue to Normal fowarding.

This is called Fast, just to differentiate the next forwarding mechanism. Because this step does not create any new objects, the next forwarding creates a Nsinvocation object, so it is relatively faster.

Normal forwarding

This step is the last time the Runtime gives you a chance to save. First it sends -methodSignatureForSelector: a message to get the function's arguments and return value types. If -methodSignatureForSelector: nil is returned, the Runtime sends -doesNotRecognizeSelector: a message, and the program is then hung out. If a function signature is returned, Runtime creates a Nsinvocation object and sends a -forwardInvocation: message to the target object.

Nsinvocation is actually a description of a message, including information such as selector and parameters. So you can -forwardInvocation: change the incoming Nsinvocation object in, then send -invokeWithTarget: a message to it, and pass in a new target:

-(void) Forwardinvocation: (nsinvocation *) invocation{    = invocation.selector;     if ([Alternateobject Respondstoselector:sel]) {        [invocation invokewithtarget:alternateobject];    }      Else {        [self Doesnotrecognizeselector:sel];    }}

Many places in Cocoa have used messaging mechanisms to extend language, such as Proxies, Nsundomanager, and Responder Chain. Nsproxy is designed to be used as a proxy for forwarding messages, Nsundomanager intercepts a message and sends it, and Responder Chain guarantees that a message is forwarded to the appropriate responder.

Summarize

Sending a message to an object in Objective-c follows several steps:

    1. Try to find the message in the dispatch table of the object class. If found, jump to the corresponding function imp to execute the implementation code;
    2. If not found, Runtime will send +resolveInstanceMethod: or +resolveClassMethod: try to resolve the message;
    3. If the Resolve method returns No,runtime, send -forwardingTargetForSelector: allows you to forward the message to another object;
    4. If no new target object is returned, Runtime sends -methodSignatureForSelector: and -forwardInvocation: messages. You can send a -invokeWithTarget: message to forward the message manually or send a -doesNotRecognizeSelector: throw exception.

Using the Objective-c runtime feature, we can expand our language to address some of the design and technical issues in project development. In the next article, I will introduce method swizzling technology and how to use method swizzling to do Logging.

Objective-c Runtime [Reprint]

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.