目标C中的“调用方法”或“发送消息”
在C或任何基于ECMAscript的语言中,您可以在对象上调用“公共方法或函数”。 但是在Objective C的文档中,没有公共的方法调用,只有发送消息。
有没有什么错误的想法,当你“发送一条消息”在ObjC中,你实际上是在一个对象上调用一个公共方法。
理论上,它们是不同的。
实际上,不是那么多。
它们在Objective-C中是不同的,对象可以select不响应消息,或者将消息转发到不同的对象,或者其他任何东西。 在像C这样的语言中,函数调用实际上只是跳到内存中的某个地方并执行代码。 没有涉及dynamic行为。
但是,在标准用例中,当您向对象发送消息时,消息表示的方法通常最终会被调用。 所以大约99%的时间,发送消息将导致调用方法。 因此,当我们真正的意思是“发送信息”时,我们经常说“打电话给方法”。 所以实际上,他们几乎总是一样的, 但他们不一定是 。
前一阵子,我在这个主题上谈了哲学,并且在博客上写道: http : //davedelong.tumblr.com/post/58428190187/an-observation-on-objective-c
编辑
要直接回答你的问题,说“调用方法”而不是“发送消息”通常没有错。 但是,重要的是要明白,有一个非常重大的实施差异。
(另外,我个人偏好是说“在对象上调用方法”)
由于Objective-C的dynamic消息调度,消息发送实际上不同于调用C函数或C ++方法(尽pipe最终将调用C函数)。 消息通过select器发送到接收对象,接收对象通过调用IMP
(一个C函数指针)或通过将消息转发给其超类来响应消息。 如果inheritance链中没有类对消息作出响应,则会引发exception。 也可以拦截一个消息并将其转发给一个完全不同的类(这就是NSProxy
子类所做的)。
在使用Objective-C的时候,消息发送和C ++风格的方法调用没有太大的区别,但是我知道消息传递系统有一些实际的含义:
- 由于消息处理是在运行时发生的,而不是编译时,所以没有编译时的方法来知道类是否响应任何特定的消息。 这就是为什么当你拼错一个方法时,你通常会得到编译器警告而不是错误。
- 你可以安全地发送任何消息给
nil
,允许像[foo release]
这样的成语而不用担心检查NULL。 - 正如@CrazyJugglerDrummer所说的,消息分派允许你一次发送消息到很多对象,而不用担心他们是否会对它们做出响应。 这允许非正式协议并将消息发送到容器中的所有对象。
- 我并不十分确定这一点,但是我认为通过dynamic的信息发布可以实现分类(向已经存在的类添加方法)。
- 消息发送允许消息转发(例如使用
NSProxy
子类)。 - 消息发送允许你做有趣的低级黑客攻击,比如方法debugging(在运行时交换方法的实现)。
不,没有这样的想法是没有错的。 它们被称为消息,因为它们是function的抽象层。 这部分来自Objective C的types系统。 更好地理解消息有助于:
维基百科上的完整源代码 (我挑出了一些更相关的问题)
该函数的内部名称很less直接使用。 通常,消息被转换为在Objective-C运行时库中定义的函数调用。 在链接时不一定知道哪个方法将被调用,因为接收器的类(被发送消息的对象)在运行之前不需要知道。
从同一篇文章:
面向对象编程的Objective-C模型是基于消息传递给对象实例的。 在Objective-C中,不会调用方法; 一个发送消息。 消息所针对的对象 – 接收者 – 不能保证对消息作出响应,如果不是,则只会引发exception。 Smalltalk风格的编程允许消息未实现,并且在运行时将方法parsing为实现。 例如,一条消息可能被发送到一个对象集合,只有一些对象将被预期响应,而不用担心产生运行时错误。 (Cocoa平台充分利用了这一点,因为应用程序启动时,Cocoa应用程序中的所有对象都会发送awakeFromNib:消息。对象可以通过在启动时执行任何初始化来响应)。消息传递也不需要定义对象在编译时。
在C函数调用中,编译器用一个函数调用replaceselect器,执行跳转以响应函数调用。
在Objective-C中,方法是dynamic绑定到消息的,这意味着方法名称在运行时parsing为实现。 具体来说,在运行时检查对象是否包含指向给定select器的实现的指针。
因此,Objective-C允许您在运行时加载和链接新的类和类别,并执行像swizzling,类别,对象代理等技术。 这在C.中是不可能的
在我的Java类中被教过 我认为他们在multithreading场景中只有真实的区别,在这种场景中,消息传递是一个非常合理和经常使用的技术。