[译]Objective-C Runtime Programming Guide -Messaging (二)


Messaging

发送消息


This chapter describes how the message expressions are converted into objc_msgSend function calls, and how you can refer to methods by name. It then explains how you can take advantage of objc_msgSend, and how—if you need to—you can circumvent dynamic binding.


本章介绍如何在消息表达式转换成objc_msgSend函数调用,以及如何通过名称来引用的方法。然后,它解释了如何利用objc_msgSend的优势,以及如何绕过动态绑定(如果你需要的话)。


The objc_msgSend Function

In Objective-C, messages aren’t bound to method implementations until runtime. The compiler converts a message expression,

[receiver message]

在Objective-C 中,消息不一定要绑定实现方法直到运行的时候。编译器会进行消息表达式的转换。

into a call on a messaging function, objc_msgSend. This function takes the receiver and the name of the method mentioned in the message—that is, the method selector—as its two principal parameters:

objc_msgSend(receiver, selector)
call一个消息函数,objc_msgSend 这个函数拿着接收者和方法的名字在消息中被提及,就是说这个方法被选择了,就像这两个主要的参数:
objc_msgSend(receiver, selector)

Any arguments passed in the message are also handed to objc_msgSend:

objc_msgSend(receiver, selector, arg1, arg2, ...)

The messaging function does everything necessary for dynamic binding:

  • It first finds the procedure (method implementation) that the selector refers to. Since the same method can be implemented differently by separate classes, the precise procedure that it finds depends on the class of the receiver.

  • It then calls the procedure, passing it the receiving object (a pointer to its data), along with any arguments that were specified for the method.

  • Finally, it passes on the return value of the procedure as its own return value.

  • Note: The compiler generates calls to the messaging function. You should never call it directly in the code you write.


任何参数被交给消息都用objc_msgSend
objc_msgSend(receiver, selector, arg1, arg2, ...)
这消息函数做一切必要的动态绑定:
它首先找到程序(方法的实现)所指的,因为同样的方法可以有不同的实现by单独的类,这个确切的过程取决于它找到的发送者的类。
然后它调用程序,通过他来接收对象(一个指向他的数据指针),以及用于该方法中指定的任何参数。
最后,通过程序的值返回值作为其自身的返回值。
备注:编译器生成调用消息的函数。你不需要在你写的代码直接调用它。

The key to messaging lies in the structures that the compiler builds for each class and object. Every class structure includes these two essential elements:

  • A pointer to the superclass.

  • A class dispatch table. This table has entries that associate method selectors with the class-specific addresses of the methods they identify. The selector for the setOrigin::method is associated with the address of (the procedure that implements) setOrigin::, the selector for the display method is associated with display’s address, and so on.

对于Messageing来说关键的结构在于编译器对于每一个类和对象的编译。每个类的结构包括两个基本元素:
一个指向父类的指针。
一个类的调度表。这个表里有识别方法类的特定地址用来联系相关联的方法选择器的条目。选择器 setOrigin:: 方法进行地址关联(一个实现过程) setOrigin:: 这个选择器用于显示方法来联系地址,依次类推。

When a new object is created, memory for it is allocated, and its instance variables are initialized. First among the object’s variables is a pointer to its class structure. This pointer, called isa, gives the object access to its class and, through the class, to all the classes it inherits from.

当创建一个对象的时候,内存被分配,其实例变量被初始化。第一个对象的变量是一个指向类结构的指针。这个指针被称作 isa,给这个目标访问类,经过这个类给所有从他这边继承的类。


Note: While not strictly a part of the language, the isa pointer is required for an object to work with the Objective-C runtime system. An object needs to be “equivalent” to astruct objc_object (defined in objc/objc.h) in whatever fields the structure defines. However, you rarely, if ever, need to create your own root object, and objects that inherit from NSObject or NSProxy automatically have the isa variable.


注意:虽然语言不是严格意义上的一部分,isa 指针需要一个在Objective-C运行时系统工作的对象。 一个对象必须是“等价于”一个struct objc_object (定义在 objc/objc.h)在任何字段的结构定义。然而,你很少这样,如果有的话,需要创建你自己的根对象,并这些对象继承于NSObject 或NSProxy 并自动的拥有isa 变量。


These elements of class and object structure are illustrated in Figure 3-1.




When a message is sent to an object, the messaging function follows the object’s isa pointer to the class structure where it looks up the method selector in the dispatch table. If it can’t find the selector there, objc_msgSend follows the pointer to the superclass and tries to find the selector in its dispatch table. Successive failures cause objc_msgSend to climb the class hierarchy until it reaches the NSObject class. Once it locates the selector, the function calls the method entered in the table and passes it the receiving object’s data structure.

This is the way that method implementations are chosen at runtime—or, in the jargon of object-oriented programming, that methods are dynamically bound to messages.

To speed the messaging process, the runtime system caches the selectors and addresses of methods as they are used. There’s a separate cache for each class, and it can contain selectors for inherited methods as well as for methods defined in the class. Before searching the dispatch tables, the messaging routine first checks the cache of the receiving object’s class (on the theory that a method that was used once may likely be used again). If the method selector is in the cache, messaging is only slightly slower than a function call. Once a program has been running long enough to “warm up” its caches, almost all the messages it sends find a cached method. Caches grow dynamically to accommodate new messages as the program runs.


当一个消息被发送到一个对象,在它查找在调度表中的方法选择器的时候,该消息传递函数跟着对象的isa指针指向类的结构。如果在这里它不能找到选择器,objc_msgSend跟着这个指针到父类中去并试着找到选择器。连续的查找失败导致objc_msgSend 向上跨越等级(继承的等级)直到到达NSObject类。一旦找到了选择器,这个函数调用在表中的方法and传递给接受对象的数据结构。

这是一种选择在运行时实现这个方法,或者说这个是面向对象编程的中术语的方法,该方法动态绑定到这个消息。

为了加快消息传递的过程,运行时系统缓存了选择器和他们使用的地址。这些都是对每个类独立的缓存,并且它可以包含选择器继承的方法以及用于在该类中定义的方法。在搜索调度表之前,消息收发程序首先检查该接收对象的类的高速缓存(在理论上可能有可能被再次使用的,使用后一方法)。如果该方法选择器是在高速缓存中,消息发送只会比一个函数调用稍微慢一点。一旦程序已经运行足够长的时间来“热身”,它的高速缓存,几乎所有发送的消息都会找到一个缓存的方法。因为程序在运行,高速缓存会动态增长以适应新的消息。



Using Hidden Arguments

When objc_msgSend finds the procedure that implements a method, it calls the procedure and passes it all the arguments in the message. It also passes the procedure two hidden arguments:

  • The receiving object

  • The selector for the method

These arguments give every method implementation explicit information about the two halves of the message expression that invoked it. They’re said to be “hidden” because they aren’t declared in the source code that defines the method. They’re inserted into the implementation when the code is compiled.


使用隐藏的参数

当objc_msgSend 找到实现的方法,它在消息中调用程序并传递参数。它在过程中还传递两个隐藏参数:

1、接收的对象

2、选择器的方法

这些参数给每一个方法的实现提供关于这两部分的消息表达式的明显的信息。他们说是“隐藏的”,因为它们不是在源代码中定义的方法声明。他们在编译时被插入到执行代码中。


Although these arguments aren’t explicitly declared, source code can still refer to them (just as it can refer to the receiving object’s instance variables). A method refers to the receiving object as self, and to its own selector as _cmd. In the example below, _cmd refers to the selector for the strange method and self to the object that receives a strangemessage.

- strange
{
    id  target = getTheReceiver();
    SEL method = getTheMethod();
 
    if ( target == self || method == _cmd )
        return nil;
    return [target performSelector:method];
}

self is the more useful of the two arguments. It is, in fact, the way the receiving object’s instance variables are made available to the method definition.


虽然这些参数没有被显式地声明,源代码仍然可以访问他们(正如它可以指到接收对象的实例变量)。一种方法使用接收的对象就像使用self一样,他拥有的选择器作为_cmd。在下面的例子中,_cmd是用于陌生方法的参考选择器且对于方法的自身是一个模式的消息。


(代码其实我也没怎么看懂)。。求指导~

self的两个参数比较有用,事实上接收对象的实例变量是被提供方法定义的方式。



Getting a Method Address

The only way to circumvent dynamic binding is to get the address of a method and call it directly as if it were a function. This might be appropriate on the rare occasions when a particular method will be performed many times in succession and you want to avoid the overhead of messaging each time the method is performed.

With a method defined in the NSObject class, methodForSelector:, you can ask for a pointer to the procedure that implements a method, then use the pointer to call the procedure. The pointer that methodForSelector: returns must be carefully cast to the proper function type. Both return and argument types should be included in the cast.


规避动态结合的唯一方法是让一个方法的地址,并直接调用它,就好像它是一个函数。这可能是适当的在极少数情况下,当一个特定的方法将被连续的执行多次,你想避免这个方法每次执行的开销。


随着NSObject类,methodForSelector中定义的方法:,你可以要求一个指向实现方法的程序,然后使用指针来调用该程序。这个methodForSelector:指针必须返回一个安全正确的函数类型。返回的参数类型必须包括在描述中。

The example below shows how the procedure that implements the setFilled: method might be called:

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);

The first two arguments passed to the procedure are the receiving object (self) and the method selector (_cmd). These arguments are hidden in method syntax but must be made explicit when the method is called as a function.

Using methodForSelector: to circumvent dynamic binding saves most of the time required by messaging. However, the savings will be significant only where a particular message is repeated many times, as in the for loop shown above.

Note that methodForSelector: is provided by the Cocoa runtime system; it’s not a feature of the Objective-C language itself.


传递给该程序的前两个参数是接收中的对象(self)和方法的选择(_cmd)。这些参数都隐藏在方法的语法中,但该方法被函数调用时必须明确。


使用methodForSelector:用消息绕过动态绑定以节省所需的大部分时间。然而,这个节省只有在一个特定的消息被重复了很多次的时候是显著的,比如如上图所示在for循环


需要注意的是methodForSelector:由Cocoa运行时系统提供的 ; 这不是Objective-C语言本身的特点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值