【问题标题】:What's the purpose of the setSelector method on the NSInvocation class?NSInvocation 类上的 setSelector 方法的目的是什么?
【发布时间】:2011-07-31 23:09:02
【问题描述】:

我不明白为什么我们必须在 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 - 很高兴在这里看到一个尚未被问(和回答)一百万次的问题,并且不是用难以理解的即时消息行话写的。 :-)
  • 一个小点:signature = [SomeObject instanceMethodSignatureForSelector:someSelector]; 应该是signature = [[SomeObject class] instanceMethodSignatureForSelector:someSelector]; or signature = [SomeObject methodSignatureForSelector:someSelector];

标签: objective-c dynamic methods language-design nsinvocation


【解决方案1】:

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

考虑以下

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

它们具有相同的选择器@selector(setLocation:),但签名不同。

- (void)setX:(CGFloat)x;
- (void)setY:(CGFloat)y;

它们具有相同的签名,但选择器不同。

来自 ObjC 编程语言的Selectors 可能是理解这一点的有用参考。

【讨论】:

  • 虽然我明白你在说什么,但语言似乎有些冗余。我设置了两次选择器(一次在签名中,再次在调用实例中)。我个人(恕我直言)认为从签名中派生选择器(在我的例子中是在someSelector 中定义的)会更有效。
  • 您不能从签名派生选择器。您可以通过询问目标从目标和选择器派生签名(请记住,新方法和类可以在运行时创建;您无法在编译时确定任何这些)。你是对的,可能有+invocationWithTarget:selector:arguments: 快捷方法(我的团队有一个添加类似内容的类别)。它不会更有效,因为它只会调用你正在调用的代码,但它会更方便一些。
【解决方案2】:

方法签名只定义返回类型,以及参数的数量和类型。它不包含有关选择器名称的任何内容。例如,所有这些方法都有相同的签名,尽管有不同的选择器:

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

【讨论】:

    【解决方案3】:

    这是一个侧面答案,但您可以执行以下操作这一事实帮助我更好地理解方法签名和选择器之间的分离。

    此代码在视图控制器中

    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,您可以使用一个选择器创建方法签名,但将调用发送给另一个。

    【讨论】:

      猜你喜欢
      • 2010-09-07
      • 2023-03-17
      • 1970-01-01
      • 2020-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多