3

对objective-c来说很新,但我遇到了似乎很常见的情况:我希望ClassA要求ClassB在只有ClassB知道的对象上执行一个方法(并且还使用ClassA未知的方法)。

我找到了两种方法:performSelector:forwardInvocation: - 但我想了解更多并巩固我对每种方法的理解。我在苹果开发者文档中找到了这个注释:

aSelector 参数 [in performSelector:] 应该标识一个不带参数的方法。对于返回对象以外的任何东西的方法,请使用 NSInvocation。

..这是否意味着以- (id)methodName开头的方法将使用performSelector:,而说- (int)nonObjectMethodName将使用forwardInvocation:

还有返回(void)的方法呢?或返回非 id 对象的方法,例如(NSString)

4

3 回答 3

7

No.-forwardInvocation:用作消息转发机制的一部分。不要担心消息转发,因为它实际上只被代理对象使用,而且很有可能你永远不需要使用它并且知道你正在使用它。

-performSelector:假定消息的返回类型是id或兼容的,因此如果它用于发送返回类型不同的消息(例如比long long32 位系统上的指针更宽,或通过不同的寄存器/地址返回),则不安全例如 afloat或 large struct。)

如果你想间接发送这样的消息,你可以创建一个类的实例NSInvocation然后发送它-invoke。然后将返回值存储在调用对象中,并可以通过它进行访问。-forwardInvocation:在这种情况下,您永远不会使用。

一般来说,如果您发现自己在使用-performSelector:,您可能正在处理反模式。在这种情况下,您正在尝试发送一条ClassA不正式知道的消息。另一种解决方案是公开这些私有方法。


如果您同时拥有ClassAand ClassB,您可以为它创建一个“私有”标头,ClassB其中包括您要使用的私有方法。如果其他人(例如 Apple)拥有ClassB,则您正在处理未记录的 API,可能需要寻找另一种方法,因为 Apple 将拒绝使用此类 API 的应用程序。

要创建私有头文件,请进入 Xcode 并创建一个新的头文件。将其命名为“ClassB+Internal.h”或“ClassB+PrivateMethodsForMeOnly.h”。将其视为您项目的私有 - 除非他们与ClassB. 在这个新标题中,添加以下内容:

#import "ClassB.h" // so we get the original class definition

@interface ClassB (PrivateMethodsForMeOnly)
- (double)someMethod;
- (const struct low_level_c_type_t)otherMethod:(int)i;
// etc. etc. etc.
@end

ClassA.m除非 ClassA.h您想向使用这些方法的每个人公开这些方法ClassA!)在您的包含部分中添加以下行:

#import "ClassB+PrivateMethodsForMeOnly.h"

ClassA此后将可以访问新类别中的这些方法。

于 2012-07-07T23:44:26.180 回答
0

好的,这是几个问题。

首先,忘记“forwardInvocation”——这几乎是一种您只需要制作代理对象的方法。

调用是用 [NSInvocation invocationWithMethodSignature...] 创建的,然后填充选择器、参数和目标对象,最终你只是“调用”它。这就是您可以发送(甚至存储)任何方法调用的方式。

performselector 存在多种变体,其中一些接受参数,在延迟后调用它,或者在另一个线程上运行该方法。这是一个更“直接”的调用——NSInvocation 是一个对象,你可以像任何其他对象一样保留它,直到你需要它,而“performselector”几乎立即运行该方法。

至于返回值,我通常坚持文档所说的;如果它告诉我该方法应该返回一个 id 我返回一个对象(任何对象指针都可以,所以 NSString* 很好。返回 nil 也可以,这几乎涵盖了“void”的情况),而不是 void 而不是 int。

另外,请记住,调用 performselector 并不常见。在大多数情况下,您只需将调用硬编码为“[MyObject SomeMethod:SomeParameter];”。调用 performSelector 样式的方法是针对特殊情况的——GUI 对象上的目标/动作内容就是这样一种情况,其中要调用的选择器存储在对象中,因此显然不能硬编码。

于 2012-07-07T23:57:07.907 回答
0

的目的-forwardInvocation:是让一个对象尝试发送一条它无法识别其他对象的消息,而不是放弃。一个 NSInvocation 不仅包含选择器,还包含消息的所有参数。NSProxy使用它,但如果我没记错的话,我们在分布式对象之前就有它。这是为“这个类无法处理的一切”实现委托的一种方法。

您应该阅读Objective-C 文档中关于消息转发的部分。

于 2012-07-08T09:36:17.053 回答