NSInvocation类中的setSelector方法的目的是什么?

10

我不明白为什么我们需要在NSInvocation对象上调用setSelector方法,当这些信息已经通过invocationWithMethodSignature传递。

要创建NSInvocation对象,我们执行以下操作:

SEL someSelector;
NSMethodSignature *signature;
NSInvocation *invocation;

someSelector = @selector(sayHelloWithString:);

//Here we use the selector to create the signature
signature = [SomeObject instanceMethodSignatureForSelector:someSelector];
invocation = [NSInvocation invocationWithMethodSignature:signature];

//Here, we again set the same selector
[invocation setSelector:someSelector];
[invocation setTarget:someObjectInstance];
[invocation setArgument:@"Loving C" atIndex:2];

请注意,我们将选择器传递给了[SomeObject instanceMethodSignatureForSelector: someSelector];并再次传递给[invocation setSelector:someSelector];

我有什么遗漏的吗?


1
+1 - 很高兴在这里看到一个问题,它还没有被问过(和回答)一百万次,并且也没有用难以理解的即时消息俚语写成。 :-) - Sherm Pendley
一个小细节:signature = [SomeObject instanceMethodSignatureForSelector:someSelector]; 应该改为 signature = [[SomeObject class] instanceMethodSignatureForSelector:someSelector]; 或者 signature = [SomeObject methodSignatureForSelector:someSelector]; - Brynjar
3个回答

8

签名不是选择器。选择器是消息的名称。签名定义了参数和返回值。您可以有许多具有相同签名的选择器,反之亦然。如果您查看NSMethodSignature,则会注意到没有-selector方法;签名不携带特定的选择器。

考虑以下情况

- (void)setLocation:(CGFloat)aLocation;
- (void)setLocation:(MyLocation*)aLocation;

他们有相同的选择器@selector(setLocation:),但是不同的签名。
- (void)setX:(CGFloat)x;
- (void)setY:(CGFloat)y;

这些具有相同的签名,但选择器不同。

ObjC编程语言中的选择器可能是理解此内容的有用参考。


虽然我理解你的意思,但是语言中似乎有些冗余。我在签名中设置了选择器两次(一次在签名中,一次在调用实例中)。个人认为更有效率的做法是从签名中推导出选择器(在我的情况下,选择器是在someSelector中定义的)。 - haroldcampbell
你不能从签名中派生选择器。但是你可以通过询问目标对象来从目标和选择器中派生出一个签名(请记住,新的方法和类可以在运行时创建;你无法在编译时确定任何内容)。你说得对,可能会有一个 +invocationWithTarget:selector:arguments: 快捷方法(我的团队有一个添加了类似功能的分类)。它不会更有效率,因为它只是调用你正在调用的代码,但它会更方便一些。 - Rob Napier

3

方法签名仅定义返回类型和参数的数量和类型,不包括选择器名称。例如,尽管具有不同的选择器,但所有这些方法具有相同的签名:

-(void) foo:(NSString*)fooString;
-(void) bar:(NSString*)barString;
-(void) baz:(NSString*)bazString;

0
这是一个侧面的回答,但事实上你可以做到以下操作,这帮助我更好地理解方法签名和选择器之间的区别。
这段代码位于视图控制器中。
NSMethodSignature *sig = nil;
sig = [[self class] instanceMethodSignatureForSelector:@selector(viewDidAppear:)];
NSInvocation *myInvocation = nil;
myInvocation = [NSInvocation invocationWithMethodSignature:sig];

[myInvocation setTarget:_somePopoverController];
[myInvocation setSelector:@selector(dismissPopoverAnimated:)];
BOOL animate = YES;
[myInvocation setArgument:&animate atIndex:2];
[myInvocation invoke];

由于UIViewController的viewDidAppear:和UIPopoverController的dismissPopoverAnimated:都需要一个BOOL参数并返回void,因此您可以使用一个选择器创建方法签名,但将调用发送到另一个选择器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接