Understanding Objective-c Runtime

Source: Internet
Author: User

http://www.justinyan.me/post/1624

Note: This is a translation of Colin Wheeler's understanding the Objective-c Runtime.

Beginners OBJECTIVE-C (hereinafter referred to as OBJC) can easily ignore a OBJC feature--OBJC Runtime. This is because the language is easy to use and can be learned in a few hours, so programmers tend to spend their time understanding the COCOA framework and adjusting their own programs. But the Runtime should be something that every OBJC should know, at least to understand that the compiler will

[target doMethodWith:var1];

Compiled into:

objc_msgSend(target,@selector(doMethodWith:),var1);

Such a statement. Understanding how the OBJC Runtime works helps you understand the OBJC language more deeply and understand how your App is running. I think all the mac/iphone developers, regardless of level, will benefit from it.

OBJC Runtime is open source.

The code for the OBJC Runtime is open source and can be downloaded from this site: opensource.apple.com.

This is a link to all open source code: http://www.opensource.apple.com/source/

This is the source code for OBJC rumtime: http://www.opensource.apple.com/source/objc4/
4 should represent a build version instead of a language version, and it is now OBJC 2.0

Dynamic vs Static Language

OBJC is a language that targets runtime (runtime), which means that whenever possible, the decision to execute the code is deferred from compile and link to runtime. This gives programmers a lot of flexibility in writing code, such as the ability to forward messages to the object you want, or to swap out the implementation of a method. This requires the runtime to detect whether an object can respond to a method, and then distribute the method to the corresponding object. Let's take C to compare with OBJC. In C, everything starts with the main function, when the programmer writes the code from top to bottom, a struct of C, or a class bar, is not able to forward method calls to other objects. Give me a chestnut:

#include < stdio.h >int main(int argc, const char **argv[]){        printf("Hello World!");        

This code is parsed by the compiler and, after optimization, becomes a bunch of assembly code:

.text .align 4,0x90 .globl _main_main:Leh_func_begin1: pushq %rbpLlabel1: movq %rsp, %rbpLlabel2: subq $16, %rspLlabel3: movq %rsi, %rax movl %edi, %ecx movl %ecx, -8(%rbp) movq %rax, -16(%rbp) xorb %al, %al leaq LC(%rip), %rcx movq %rcx, %rdi call _printf movl $0, -4(%rbp) movl -4(%rbp), %eax addq $16, %rsp popq %rbp retLeh_func_end1: .cstringLC: .asciz "Hello World!"

Then, you link the Include library, and you're done generating executable code. In contrast to OBJC, when we're learning the language, the tutorial says, "in parentheses,

[self doSomethingWithVar:var1];

After being compiled by the compiler, it becomes:

objc_msgSend(self,@selector(doSomethingWithVar:),var1);

A C method, passed three variables, the self pointer, the method to be executed @selector (Dosomethingwithvar:) There is also a parameter var1. But after that, I don't know what's going on.

What is Objective-c Runtime?

OBJC runtime is actually a runtime library, basically written in C and sink, this library makes C language has the object-oriented ability (the brain emerges when you Joe Master visited Xerox Parker's SmallTalk after the mouth of a smile). This library does the pre-loading of the class information, the method of distribution and forwarding and so on.

Objective-c Runtime Terminology

Let's introduce a few terms before we go down Deepin talk.

  • 2 runtimes

    There are two types of runtime, a modern runtime and a Legacy runtime. The modern runtime covers 64-bit Mac OS X apps, and IOS apps,legacy Runtime is used earlier for 32-bit Mac OS X apps, which means you don't have to worry about it.

  • 2 Basic Types of Methods

    A Instance method, and a Class method. Instance method is with the "-" number, need to instantiate to use, such as:

    -(void)doFoo; [aObj doFoot];

    Class method is a "+" number, similar to a static method can be called directly:

    +(id)alloc;[ClassName alloc];

    These methods, like the C function, are a set of code that accomplishes a relatively small task.

    -(NSString *)movieTitle{    return @"Futurama: Into the Wild Green Yonder";}
  • Selector

    A Selector is actually a struct of C, which represents a method. Definitions are:

    typedef struct objc_selector  

    The use is:

    This allows you to take a selector directly, if you are passing a message (a method call similar to C) is:

    [target getMovieTitleForObject:obj];

    In OBJC, an expression enclosed in ' [] ' is a message. Includes a target, the object to receive the message, a method to be called, and some arguments you want to pass. A call similar to a C function, but different. In fact, the above statement simply conveys the OBJC message and does not necessarily mean that it will be executed. Target This object detects who initiated the request, and then the decision is to execute the method or another method, or forward it to another object.

  • Class

    The definition of Class is this:

    typedef struct objc_class *Class;typedef struct objc_object {    

    We can see here there are two structures, a class structure, an object structure. All Objc_object object structures have an Isa pointer that points to the class to which it belongs, and this pointer is used at run time to detect if the object can respond to a selector. It's over. We see an ID pointer at the end. This pointer is simply used to represent a OBJC object, a bit similar to C + + generics. Once you have an ID pointer, you can get the class of the object and detect if it responds to a selector. This is the usual way to call a delegate. This is a bit of an abstraction, let's look at the definition of Blocks in Llvm/clang's documentation:

     struct Block_literal_1 {    void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock    int flags;    int reserved;     void (*invoke)(void *, ...);    struct Block_descriptor_1 { unsigned long int reserved; // NULL     unsigned long int size;  // sizeof(struct Block_literal_1) // optional helper functions     void (*copy_helper)(void *dst, void *src);     void (*dispose_helper)(void *src);     } *descriptor;    // imported variables};

    You can see that a block is designed to be an object with an Isa pointer, so you can use retain, release, and copy these methods on a block.

  • IMP (Method implementations)

    Next look at what is imp.

    An IMP is a function pointer, which is generated by the compiler, and when you start a OBJC message, the code that eventually executes is specified by the function pointer.

  • Objective-c Classes

    OK, look back at a OBJC class. Lift a chestnut:

    @interface MyClass : NSObject {//varsNSInteger counter;}//methods-(void)doFoo;@end

    Defining a class we can write as code, and at run time, a class is not just what we see above:

    #if !__OBJC2__    Class super_class                                        OBJC2_UNAVAILABLE;    const char *name                                         OBJC2_UNAVAILABLE;    long version                                             OBJC2_UNAVAILABLE;    long info                                                OBJC2_UNAVAILABLE;    long instance_size                                       OBJC2_UNAVAILABLE;    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;    struct objc_protocol_list *protocols                     

    You can see that at runtime a class also associates its parent class pointer, class name, member variable, method, cache, and subordinate protocol.

So the class defines the object and is itself an object? What is this whole drop?

I mentioned above that a OBJC class is also an object, in order to handle the relationship between classes and objects, the runtime library creates something called the tag class meta class. When you send a message, let's say

[NSObject alloc];

You actually sent this message to a class object, which must be an instance of a meta class, and this meta class is also an instance of the root metaclass. When you inherit NSObject as its subclass, your class pointer points to NSObject as its parent class. But the Meta class is different, and all meta classes point to the root meta class for its parent class. A Meta Class holds all the methods that can be responded to. So when [NSObject alloc] This message is issued, Objc_msgsend () This method will nsobject its Meta class to find out if there is a way to respond to this selector, and then to nsobject this class object execution Method invocation.

Why do we inherit Apple Classes

Beginners Cocoa Development, most of the tutorials we have to inherit a class analogy nsobject, and then we began to Coding. Say:

MyObject *object = [[MyObject alloc] init];

This statement is used to initialize an instance, similar to the new C + + keyword. This statement first executes the +alloc method of the MyObject class, as Apple's official document says:

The ISA instance variable of the new instance is initialized to a data structure that describes the class; Memory for all and instance variables is set to 0.

In the newly created instance, the ISA member variable is initialized to a data structure body that describes the class to which it is pointing. The memory of the other member variables is set to 0.

So inheriting Apple's class we not only obtained a lot of good properties, but also inherited this method of memory allocation.

So what is Class Cache (Objc_cache *cache)

Just now we see that there is a pointer in the runtime called Objc_cache *cache, which is used to cache method calls. Now that we know that an instance object is being passed a message, it will look for an object that responds to the message according to the ISA pointer. But in fact, when we use, only a part of the method is commonly used, many methods are seldom used or not used at all. Like an object you may never use the Copy method, so I would be foolish to walk through all the methods every time I call. So the cache came into being, every time you call a method, then the method will be stored in the cache list, the next time the runtime will be the first to go to the cache to find, improve the efficiency of the call. Lift a chestnut:

MyObject *obj = [[MyObject alloc] init]; // MyObject 的父类是 NSObject@implementation MyObject-(id)init {    if(self = [super init]){        [self setVarA:@”blah”];    }    return self;}@end

This code is executed in this way:

    1. [MyObject Alloc] is executed first. But because MyObject this class does not have +alloc this method, then goes to the parent class NSObject to find.
    2. Detects if the nsobject responds to the +alloc method, finds the response, detects the MyObject class, starts allocating memory space based on the amount of memory it needs, and then points the ISA pointer to the MyObject class. Then +alloc is added to the cache list.
    3. The-init method is executed because MyObject responds to the method and joins the cache directly.
    4. Executes the self = [super init] statement. The Init method of the parent class is called directly from the Super keyword, ensuring that the parent class initializes successfully and then executes its own initialization logic.

OK, this is a very simple initialization process, in the NSObject class, alloc and init do not do anything particularly important, but, the OBJC feature allows you to Alloc and init return values are different, that is, you can do in your init function in some very complex initial Start the operation, but returns a simple object, which hides the complexity of the class. Give me another chestnut:

  #import < foundation/foundation.h> @interface myobject:nsobject{nsstring *astring;} @property (retain) nsstring *astring; @end @implementation myobject-(ID) init{if (self = [super init]) {[Self Setastring:ni L]; } return self;} @synthesize astring; @endint Main (int argc, const char * argv[]) {NSAutoreleasePool * pool = [NSAutoreleasePool alloc ] init]; ID obj1 = [nsmutablearray alloc]; ID obj2 = [[Nsmutablearray alloc] init]; ID obj3 = [nsarray alloc]; ID OBJ4 = [[Nsarray alloc] initwithobjects:@ "Hello", nil]; NSLog (@ "Obj1 class is%@", Nsstringfromclass ([Obj1 class]); NSLog (@ "Obj2 class is%@", Nsstringfromclass ([Obj2 class]); NSLog (@ "Obj3 class is%@", Nsstringfromclass ([Obj3 class]); NSLog (@ "Obj4 class is%@", Nsstringfromclass ([Obj4 class]); ID obj5 = [MyObject alloc]; ID obj6 = [[MyObject alloc] init]; NSLog (@ "Obj5 class is%@", Nsstringfromclass ([Obj5 class]); NSLog (@ "Obj6 class is%@", Nsstringfromclass ([Obj6 class]);    [Pool drain]; return 0;}  

If you are a beginner of OBJC, you will probably think that the output of this code will be:

NSMutableArrayNSMutableArray NSArrayNSArrayMyObjectMyObject

But the truth is this:

obj1 class is __NSPlaceholderArrayobj2 class is NSCFArrayobj3 class is __NSPlaceholderArrayobj4 class is NSCFArrayobj5 class is MyObjectobj6 class is MyObject

This is because OBJC is allowed to run +alloc to return a particular class, and the Init method returns a different class. You can see that Nsmutablearray is the encapsulation of ordinary arrays, the internal implementation is complex, but the external hidden complexity.

OK say back to objc_msgsend this method

This method does a lot of things, lifting a chestnut:

[self printMessageWithString:@"Hello World!"];

This statement is compiled like this:

objc_msgSend(self,@selector(printMessageWithString:),@"Hello World!");

This method first finds out whether the object or its parent responds to the @selector (printmessagewithstring:), and if it is found in the method sub-publication of this class or in the cache, it calls its corresponding function pointer. If you can't find it, you'll do something else. The steps are as follows:

    1. Detection of this selector is not to be ignored. such as Mac OS X development, with garbage collection will ignore retain, release these functions.
    2. Detects if this target is a nil object. The OBJC feature is that allowing any method to execute on a nil object is not Crash, because it is ignored.
    3. If the above two are over, then start looking for this kind of IMP, first from the cache inside the search, and then jump to the corresponding function to execute.
    4. If the cache can't find it, find a way to publish it.
    5. Start the message forwarding logic if you can't find it yet.

At compile time, you define methods such as:

is compiled into:

The runtime then invokes the function pointer that points to your method. So before we say that you started the message is not a direct call to the method, in fact, Cocoa still provides a method that can be called directly:

If you need to, you can make sure that this method is guaranteed to be invoked in this way.

Message forwarding mechanism

In the OBJC language, sending a message to an object that does not respond to this method is legal and should be deliberately designed. In other words, I can pass any message to any object (it looks a bit like calling any of the methods on any of the classes, of course not), and of course, if you can't find a method that can be called at the end, it Crash out.

One of the reasons Apple designed this mechanism is to simulate multiple inheritance (OBJC does not support multiple inheritance). Or you want to hide your complex design. This forwarding mechanism is a very important feature of Runtime, and the approximate steps are as follows:

  1. Finds the Cahce and method Sub-publication of the class and its parent class, and executes 2 if it is not found.
  2. The
  3. Execute + (BOOL) Resolveinstancemethod: (SEL) Asel method.

    This gives the programmer a chance to tell the runtime what to do if the change method is not found. For a chestnut, first define a function:

      void Foomethod (id obj, SEL _cmd) {NSLog (@ "Doing Foo");  

    Finished overloading the Resolveinstancemethod method:

      + (BOOL) Resolveinstancemethod: (SEL) asel{if (Asel = = @selector (dofoo:)) {Class_addmethod ([self class],a        SEL, (IMP) Foomethod, "[email protected]:");    return YES; } return [Super Resolveinstancemethod];}  

    [email protected]: Represents the return value and parameter, which involves Type Encoding, and can refer to Apple's documentation &NBSP;OBJC Runtime Guide.

  4. Next Runtime calls – (ID) Forwardingtargetforselector: (SEL) Aselector method.
    This gives the programmer a second chance, and if you can't find a workaround in your class, you can reload the method and pass the message to the other object.

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

    So you can pass the message on to someone else. Of course, you can't return self here, or you'll die. =.=

  5. Finally, Runtime calls the-(void) Forwardinvocation: (nsinvocation *) Aninvocation this method. Nsinvocation is actually a package of messages. If you can get nsinvocation, you can modify the message target, selector and arguments. Give me a chestnut:
    -(void)forwardInvocation:(NSInvocation *)invocation{    SEL invSEL = invocation.selector;    if([altObject respondsToSelector:invSEL]) {        [invocation invokeWithTarget:altObject];    } else {        [self doesNotRecognizeSelector:invSEL];    }}

    By default NSObject's implementation of Forwardinvocation is simply to execute-doesnotrecognizeselector: This method, so if you want to actually forward the message at the last minute you can reload this method (good toss-.-).

    The original text describes the Non fragile Ivars (modern Runtime), objective-c associated Objects and Hybrid vTable Dispatch. In view of one is the bottom of the can not be ignored, one is the early commonplace, there is a very simple, is a method is built in the publication of the default methods, so interested readers can check the original text, here do not talk about birds.

Understanding Objective-c Runtime

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.