The message of cocoa in layman's

Source: Internet
Author: User

The message of cocoa in layman's

Roche (http://www.cnblogs.com/kesalin/)

This article follows "Attribution-non-commercial use-consistent" authoring public agreement

In the introductory-level OBJC tutorial, we often say to programmers who have turned from C + + or Java or other object-oriented languages that a method call in OBJC (the term in OBJC is a message) is similar to a method invocation in another language, except that the form is somewhat different.

For example, in C + +:

Bird * Abird = new Bird ();

Abird->fly ();

In OBJC, the following is true:

Bird * Abird = [[Bird alloc] init];

[Abird fly];

At first glance, it seems that the writing form is different, but the difference is big. Method invocations in C + + can be dynamic or static, while messages in OBJC are dynamic. The following details explain why it's dynamic and what the compiler does behind it.

To be clear about this topic, we must first understand the three concepts class, SEL, IMP, which are defined in objc/objc.h:

typedef struct OBJC_CLASS *class;

typedef struct OBJC_OBJECT {

Class Isa;

} *id;

typedef struct OBJC_SELECTOR *sel;

typedef ID (*IMP) (ID, SEL, ...);

The meaning of Class

Class is defined as a pointer to the OBJC_CLASS structure that represents the class structure of each class. and Objc_class is defined in Objc/objc_class.h as follows:

struct Objc_class {

struct Objc_class * ISA;

struct Objc_class * super_class; /* Parent class */

const char *name; /* Class name * *

Long version; /* Version information */

Long info; /* Class Information * *

Long instance_size; /* Instance size */

struct Objc_ivar_list *ivars; /* instance parameter chain list */

struct Objc_method_list **methodlists; /* method Chain list */

struct Objc_cache *cache; /* Method Cache */

struct Objc_protocol_list *protocols; /* Protocol link list */

};

This shows that class is a pointer to a class struct that contains a pointer to its parent class structure, a linked list of methods, the caching of such methods, and other necessary information.

The NSObject class method returns a pointer to its class structure. The first instance variable of each class instance object is a pointer to the class structure of the object, called Isa. With this pointer, the object can access its corresponding class and the corresponding parent class. One of the following:

As shown, the first instance variable of the instance object represented by the circle is Isa, which points to the class structure of the class the object ' s class. The class structure has a pointer to its parent class structure, superclass, and a method chain list of its own message name (selector)/implementation address.

Meaning of the method:

Note that the methods listed here are stored in the method list. The selector in Figure one refers to the SEL of method, the address means the IMP of method. Method is defined in the header file Objc_class.h as follows:

typedef struct OBJC_METHOD *method;

typedef struct OBJC_ Method {

SEL method_name;

Char *method_types;

IMP Method_imp;

};

A method that contains a method that sel– represents the name of the method, a types– represents the type of the method parameter, a IMP-pointer to a function that points to the specific implementation of the method.

What the SEL means:

In the preceding we see the definition of the method selection SEL as:

typedef struct OBJC_SELECTOR *sel;

It is a pointer to the Objc_selector that represents the name/signature of the method. Print out the selector as shown below.

-(Nsinteger) Maxin: (Nsinteger) a theother: (Nsinteger) b

{

Return (a > B)? A:B;

}

NSLog (@ "sel=%s", @selector (Maxin:theother:));

Output: Sel=maxin:theother:

Different classes can have the same selector, which is not a problem, because instance objects of different classes performselector the same selector, in the respective message selection (selector)/Implementation Address method list according to Selector to find a specific method to implement IMP, and then use this method to implement the implementation of specific code. This is a dynamic binding process, at compile time, we do not know what will eventually execute some code, only when executing, through the selector to query, we can determine the specific execution code.

Meaning of IMP:

In the preceding we also see the definition of IMP as:

typedef ID (*IMP) (ID, SEL, ...);

Based on the definition of the previous ID, we know that the ID is a pointer to the Objc_object struct, which has only one member of ISA, so any class object that inherits from NSObject can be referred to by ID, because the first member instance of NSObject is Isa.

At this point, we know exactly what IMP means: IMP is a function pointer that contains an object ID (self pointer) that receives a message, an optional SEL (method name) that invokes the method, and an indefinite number of method parameters, and returns an ID. That is, the IMP is the execution code of the final invocation of the message and is the actual implementation code of the method. We can use this function pointer in the same way as in the C language.

Methodforselector in the NSObject class: The method is to get a pointer to the method implementation imp, Methodforselector: The returned pointer and the assigned variable type must be exactly the same, including the method's parameter type and the return value type.

The following example shows how to use pointers to invoke the setfilled: method implementation:

void (*setter) (ID, SEL, BOOL);

int i;

Setter = (void (*) (ID, SEL, BOOL)) [Target methodforselector: @selector (setfilled:)];

for (i = 0; i <; i++)

Setter (Targetlist[i], @selector (setfilled:), YES);

Using Methodforselector: To avoid dynamic binding will reduce the overhead of most messages, but this only makes sense if the specified message is repeatedly sent many times, such as the For loop above.

Note that Methodforselector: is the functionality provided by the Cocoa runtime system, not the functionality of the Objective-c language itself.

Message invocation procedure:

Now we should have a general idea of the message in OBJC: Example

Bird * Abird = [[Bird alloc] init];

[Abird fly];

In the call to fly in, the compiler by inserting some code into the method to implement the implementation of the IMP call, the IMP is found in the Bird class structure in the method chain list to find the name of fly of the selected SEL corresponding to the specific method implemented.

There are some topics that are not mentioned above, such as what code the compiler inserted, and what happens if the corresponding IMP is not found in the method list.

Message function Obj_msgsend:

The compiler converts the message into a call to the message function Objc_msgsend, which has two main parameters: the message receiver ID and the message corresponding to the method of selecting the SEL, and receiving any parameters in the message:

ID objc_msgsend (ID thereceiver, Seltheselector, ...)

As the above message [Abird fly] is converted to a function call in the following form:

Objc_msgsend (Abird, @selector (fly));

The message function does all the work required for dynamic binding:

1, it first finds the SEL corresponding method to implement IMP. Because different classes may have different implementations for the same method, the method implementations found depend on the type of the message receiver.
2, then pass the message receiver object (pointer to the message receiver object) and the parameters specified in the method to the method implementation IMP.
3, finally, the return value of the method implementation is returned as the return value of the function.

The compiler automatically inserts the code that invokes the message function Objc_msgsend, and we do not need to display the message function in code. When Objc_msgsend finds the implementation of the method, it calls the method implementation directly and passes all parameters in the message to the method implementation, and it also passes two hidden parameters: the recipient of the message and the method name SEL. These parameters help method implementations get information about the message expression. They are considered "hidden" because they are not declared in the source code of the definition method, but rather in the implementation of the Insert method when the code is compiled.

Although these parameters are not declared, they can still be referenced in the source code (just as you can refer to instance variables of the message receiver object). The message receiver object can be referenced by self in the method, and the method itself is referenced by the _cmd. In the following example, _cmd refers to the strange method, and self refers to the object that receives the strange message.

-Strange

{

ID target = Getthereceiver ();

SEL method = Getthemethod ();

if (target = = Self | | mothod = = _cmd)

return nil;

return [target Performselector:method];

}

Self is more useful in these two parameters. In fact, it is the way to access instance variables of the message receiver object in the method implementation.

To find the IMP process:

As I said earlier, Objc_msgsend will find methods to implement IMP in the method list of the class structure based on the method selection SEL. There are some articles here, and we see in the previous class structure that there is a member called Objc_cache *cache, a cache that exists to improve efficiency. Each class has a separate cache, including inherited methods and methods defined in the class:

When looking up IMP:

1, first go to the method of the class cache to find, if found, return it;

2, if not found, go to the list of methods in the class to find. If found in the method list of the class, the IMP is returned and cached in the cache. Based on the most recent usage principle, this method is more likely to be called again, and caching can save the cost of the next call to find again. 3,3, if the corresponding IMP is not found in the method list of the class, the Super_class pointer in the class structure is searched in the method list of its parent class structure until the corresponding IMP is found in the method list of a parent class, returned to it, and added to the cache.

4, if the corresponding IMP is not found in the list of methods for itself and all the parent classes, enter the message forwarding process to be described below.

Convenience function:

We can get run-time information or execute some messages dynamically through some methods of NSObject:

Class that returns the object;

Iskindofclass and Ismemberofclass Check whether the object is in the specified class inheritance system;

Respondstoselector check whether the object can specify the corresponding message;

Conformstoprotocol Check whether the object implements the method of specifying the Protocol class;

Methodforselector returns the address of the specified method implementation.

Performselector:withobject executes the method that the SEL refers to.

  

Message forwarding:

Typically, sending a message to an object that it cannot process will get an error prompt, however, the OBJECTIVE-C runtime sends a special message forwardinvocation to the message receiving object to notify the object before it throws an error. The only argument to the message is an object of type Nsinvocation-the object encapsulates the parameters of the original message and message. We can implement the Forwardinvocation: method to do some default processing of messages that cannot be processed, or to forward messages to other objects for processing without throwing an error.

With regard to the role of message forwarding, consider the following scenario: Suppose we need to design an object that responds to negotiate messages and can include other types of objects responding to messages. It is easy to achieve this by forwarding the negotiate message to other objects in the implementation of the Negotiate method.

Further, suppose we want our object and the object of another class to have exactly the same response to the Negotiate message. One possible way is for our class to inherit the methods of other classes. Then, sometimes this is not possible because our classes and other classes may need to respond to negotiate messages in different inheritance architectures.

Although our class cannot inherit the Negotiate method of other classes, we can still provide a method implementation that simply forwards the negotiate message to other classes of objects as if it were "borrowed" from other classes. As shown below:

-Negotiate

{

if ([Someotherobject respondstoselector: @selector (Negotiate)])

return [Someotherobject negotiate];

return self;

}

This approach appears to be inflexible, especially when many messages are expected to be passed to other objects, and we must provide a method implementation for each message. In addition, this method cannot handle unknown messages. When we write down the code, all the sets of messages we need to forward must be determined. In practice, however, this collection changes as the runtime event occurs, the new method, or the definition of the new class.

Forwardinvocation: The message provides a more specific, dynamic solution to this problem: When an object is unable to respond to a message because there is no corresponding method implementation, the runtime system notifies the object by forwardinvocation: message. Each object inherits the Forwardinvocation: Method from the NSObject class. However, the method implementation in NSObject simply calls the Doesnotrecognizeselector:. By implementing our own Forwardinvocation: method, we can forward the message to other objects in the implementation of the method.

To forward a message to another object, Forwardinvocation: The method must do the following:

1, decide who to forward the message to, and
2. Forward the message with the original parameter.

Messages can be forwarded via the Invokewithtarget: method:

-(void) Forwardinvocation: (nsinvocation *) aninvocation

{

if ([Someotherobject respondstoselector:[aninvocation selector]])

[Aninvocation Invokewithtarget:someotherobject];

Else

[Super Forwardinvocation:aninvocation];

}

The return value after the message is forwarded is returned to the original message sender. You can return any type of return value, including: ID, struct, floating-point number, and so on.

Forwardinvocation: The method is like a distribution center for unrecognized messages that forwards these messages to different receive objects. Or it can send all messages to the same receiving object like a transport station. It can translate a message into another message, or simply "eat" some messages, so there is no response and no error. Forwardinvocation: Methods can also provide the same response to different messages, all depending on the implementation of the method. The method provides the ability to link different objects to the message chain.

Note: The Forwardinvocation: method is called only if the message is not responding properly in the message receiving object. So, if we want an object to forward negotiate messages to other objects, this object cannot have the Negotiate method. Otherwise, forwardinvocation: it will not be possible to be called.

Message Forwarding Example:

Proxy@interface proxy:nsobject-(void)Missmethod; @end @implementation proxy-(void) missmethod{NSLog    (@ ">> Missmethod () in Proxy."); @end//Foo@interface foo:nsobject@end@implementation foo-(void)forwardinvocation:(nsinvocation *) aninvocation{    SEL name = [aninvocation selector];    NSLog (@ ">> forwardinvocation for selector [%@]", Nsstringfromselector (name));        Proxy * proxy = [[[Proxy alloc] init] autorelease];    if ([proxy respondstoselector:name]) {        [aninvocation invokewithtarget:proxy];    }    else {        [super forwardinvocation:aninvocation];}    } -(Nsmethodsignature *)methodsignatureforselector:(SEL) aselector {    return [Proxy Instancemethodsignatureforselector:aselector];} @end//Call code foo * foo = [[[foo alloc] init] autorelease]; [foo Missmethod];

Running the above calling code will output:

>> forwardinvocation Missmethod

>> Missmethod () in Proxy.

Resources:

Objective-cruntime Reference:

http://developer.apple.com/library/mac/#documentation/cocoa/reference/objcruntimeref/reference/reference.html

Objective-c Runtime Programming Guide:
http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/objcruntimeguide/introduction/introduction.html

The message of cocoa in layman's

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.