methodSignatureForSelector可以创建一个“catch-all”方法签名吗?

时间:2012-03-30 23:10:07

标签: objective-c cocoa objective-c-runtime

我正在尝试创建一个包含任何类型参数的任何选择器的catch-all代理,并在线路上发送RPC调用。在这种情况下,方法的签名是未知的,因为它可以由最终用户任意创建。

我看到方法签名需要为每个参数提供类型编码。是否有类型编码表示绝对任何东西(指针,int,其他所有)?否则,还有另一种方法来实现这种效果吗?

2 个答案:

答案 0 :(得分:2)

“有点”,但不是真的...或者,至少,实际上并非如此。

您可以实现方法转发协议,使得无法识别的方法调用将被包含在NSInvocation中,然后您可能会进入NSInvocation,但由于多种原因它实际上是不切实际的。

首先,它只适用于相对简单的参数类型。 C ABI使得复杂的参数 - 结构,C ++对象等 - 可以以不同的方式在堆栈上进行编码。事实上,它们可以用没有足够元数据来解码帧的方式进行编码。

其次,任何一种“用户可以任意创造选择器”的系统都有一个非常明显的气味;一种“你正在艰难地做着”的气味。 Objective-C虽然异常动态,但实际上并不是为了支持这种纯粹的元对象模式而设计的。

同样,任何这样的结果系统都将非常脆弱。如果“任意选择器”恰好是@selector(hash)?

,该怎么办?

答案 1 :(得分:2)

您能否更详细地描述这个全能代理以及需要转发的内容?

如果您的代理只需要将每条消息转发到一个目标,那么它可以在运行时-forwardingTargetForSelector:中执行此操作。如果不是(例如,您需要转发到多个目标或执行其他复杂操作),则需要实现-forwardInvocation:来处理它。使用-forwardInvocation:来处理调用需要您实现-messageSignatureForSelector:,因为它需要获取方法签名才能创建调用。 (即使您将其转发给另一个对象,该对象也需要直接实现该方法,添加方法以响应+resolveInstanceMethod:,或使用-forwardInvocation:处理它,所有这些都需要它有签名。)

方法签名对参数类型和返回类型进行编码。调用需要此信息的原因是,当传递这些参数时,它们将根据声明中的类型在编译时(可能是连续)在内存中进行布局。大型struct参数占用的空间比int参数多。 double也可能比int大。调用需要存储所有这些参数,并允许您通过索引访问或更改它们。除非你知道类型(或至少是类型的大小),否则无法弄清楚参数在运行时的布局方式。

此外,对于从其他方法(它们调用objc_msgSend_stret)返回结构(它们调用objc_msgSend)的方法,消息传递机制是不同的(在某些平台上,返回双精度的方法使用{{ 1}})。在前一种情况下,结构不是直接返回的,但是要写入的位置作为额外的指针参数作为out参数传递。因此,了解返回类型对于处理调用和调用中的返回值也很重要。

即使您将调用转发给其他对象,最终该对象(或者它转发到该行的某个对象)也必须以某种方式知道方法签名。那么为什么不在需要时请求该对象签名选择器呢?

没有“安全”签名可以适用于所有事情,因为不同类型的大小不同。