Objective-C:调用具有多个参数的选择器


142

在MyClass.m中,我定义了

- (void) myTest: (NSString *) withAString{
    NSLog(@"hi, %@", withAString);
}

以及MyClass.h中的适当声明。以后我想打电话

[self performSelector:@selector(mytest:withAString:) withObject: mystring];

在MyClass.m中,但由于未捕获的异常'NSInvalidArgumentException'而收到类似于*终止应用程序的错误 ,原因:'* -[[MyClass myTest:withAtring:]:无法识别的选择器已发送到实例0xe421f0'

我用一个选择器尝试了一个更简单的情况,该选择器不带任何参数,该参数将字符串打印到控制台,并且工作正常。代码有什么问题,我该如何解决?谢谢。


4
您的帖子询问的是“多个参数”,但您只能使用一个。现在我很好奇,有人会用多个参数来做到这一点,而不是将它们包装在数组/ dict /任何东西中。
RonLugge 2012年

Answers:


137

您的方法签名是:

- (void) myTest:(NSString *)

withAString恰好是参数(名称具有误导性,它看起来像是选择器签名的一部分)。

如果以这种方式调用该函数:

[self performSelector:@selector(myTest:) withObject:myString];

会的。

但是,正如其他发布者所建议的那样,您可能需要重命名该方法:

- (void)myTestWithAString:(NSString*)aString;

并致电:

[self performSelector:@selector(myTestWithAString:) withObject:myString];

2
现在我看到人们从这个答案中受益了,我已经回顾了我的回答;我建议该调用只需:-(void)testWithString:(NSString *)aString;
林德西·弗格森

313

在Objective-C中,选择器的签名包括:

  1. 方法的名称(在本例中为“ myTest”)(必需)
  2. 如果方法具有输入,则在方法名称后加':'(冒号)。
  3. 每个其他输入的名称和“:”。

选择器不了解以下内容:

  1. 输入类型
  2. 方法的返回类型。

这是一个类实现,其中performMethodsViaSelectors方法通过选择器执行其他类方法:

@implementation ClassForSelectors
- (void) fooNoInputs {
    NSLog(@"Does nothing");
}
- (void) fooOneIput:(NSString*) first {
    NSLog(@"Logs %@", first);
}
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second {
    NSLog(@"Logs %@ then %@", first, second);
}
- (void) performMethodsViaSelectors {
    [self performSelector:@selector(fooNoInputs)];
    [self performSelector:@selector(fooOneInput:) withObject:@"first"];
    [self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second"];
}
@end

您要为其创建选择器的方法只有一个输入,因此您可以为它创建一个选择器,如下所示:

SEL myTestSelector = @selector(myTest:);

3
好答案。为了稍微说明一下,选择器名称必须至少包含一部分,该部分可以带或不带参数-如果有,则必须带一个冒号。具有两个或更多部分的选择器名称必须在每个部分后都带有一个冒号-使用“ -useFoo:andBar:toDoSoSomething”形式的选择器是不合法的。
奎因·泰勒

谢谢你 香港专业教育学院一直为此努力,很高兴获得帮助!
詹姆斯·霍尔

输入参数是整数怎么办?在这种情况下该怎么办?
Hoang Pham

1
您需要将整数包装在NSNumber对象中(请参阅developer.apple.com/library/ios/#documentation/Cocoa/Reference/…),然后在被调用方法的主体中检索整数值。它可能有点冗长(而且我还没有找到更好的方法解决),但是效果很好。
Shane Arney

30
+100:太棒了!我不知道是否可以使用多个“ withObject:”参数。如果可以的话,我会
投票

13

@Shane Arney

performSelector:withObject:withObject:

您可能还想提到此方法仅用于传递最多2个参数,并且不能延迟。(例如performSelector:withObject:afterDelay:)

有点奇怪,苹果只支持2个要发送的对象,并没有使其更通用。


2
谢谢(你的)信息。我无法耽误工作时间,现在我知道为什么了。仅供参考,为了避开两个对象的限制,我传递了一个数组,然后在方法中使用了它。
JScarry 2015年

7

您的代码有两个问题。一个被确定并回答,但另一个没有。首先是您的选择器缺少其参数名称。但是,即使您修复了该错误,该行仍将引发异常,假设您修改后的方法签名仍然包含多个参数。假设您的修订方法声明为:

-(void)myTestWithString:(NSString *)sourceString comparedTo:(NSString *)testString ;

为采用多个参数的方法创建选择器是完全有效的(例如@selector(myTestWithString:comparedTo :))。但是,performSelector方法仅允许您将一个值传递给myTest,不幸的是,myTest具有多个参数。它会出错,并告诉您您没有提供足够的值。

您始终可以重新定义方法以采用集合,因为它是唯一的参数:

-(void)myTestWithObjects:(NSDictionary *)testObjects ;

但是,有一个更优雅的解决方案(不需要重构)。答案是使用NSInvocation以及它的setArgument:atIndex:invoke方法。

如果您需要更多详细信息,我已经写了一篇文章,包括一个代码示例。重点是线程,但是基础仍然适用。

祝好运!


3

您的方法签名没有意义,您确定它不是错字吗?我不清楚它是如何编译的,尽管您可能正在收到忽略的警告?

您希望此方法采用多少个参数?


对不起,您正在写。我把它打出来,试图简化它,而不是复制并粘贴我的代码,但是我在过程中犯了一个错误。我期望这种方法采用一个参数。我要打印的字符串。
Stu

2

认为该类应定义为:

- (void) myTestWithSomeString:(NSString *) astring{
    NSLog(@"hi, %s", astring);
}

您只有一个参数,因此应该只有一个:

您可能还想考虑在NSLog中使用%@-这是一种很好的习惯-然后会写出任何对象-而不仅仅是字符串。


-1

iOS用户也希望自动大写:在标准文本字段中,区分大小写的语言的句子首字母自动大写。

您可以决定是否实施此类功能;上面列出的任何功能都没有专用的API,因此提供这些功能具有竞争优势。

苹果文档说,自定义键盘上没有此功能和某些其他预期功能可用的API。因此您需要找出自己的逻辑来实现。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.