Objective-C: 使用多个参数调用选择器

在 MyClass.m 中,我定义了

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

以及 MyClass.h 中的适当声明

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

但是我得到了一个类似于 * 由于未捕获异常“ NSInvalidArgumentException”而终止应用程序,原因: “ * -[ MyClass myTest: withAtring: ] : 发送到实例0xe421f0的未识别选择器”

我尝试了一个更简单的例子,使用一个不带参数的选择器,将一个字符串打印到控制台,这样就可以很好地工作。代码出了什么问题,我该如何修复它?谢谢。

220088 次浏览

我认为这个类应该定义为:

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

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

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

你的方法签名没有任何意义,你确定这不是打印错误吗?我甚至不清楚它是如何编译的,尽管也许你得到的警告是你忽略的?

您希望此方法接受多少参数?

你的方法签名是:

- (void) myTest:(NSString *)

WithAString 恰好是这个参数(名称有误,它看起来像是选择器签名的一部分)。

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

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

会成功的。

但是,正如其他海报所建议的那样,你可能需要重新命名这种方法:

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

打电话给:

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

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

  1. 方法的名称(在本例中为‘ myTest’)(必需)
  2. 如果方法具有输入,则方法名后面的’:’(冒号)。
  3. 每个额外输入的名称和’:’。

选择者不知道:

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

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

@implementation ClassForSelectors
- (void) fooNoInputs {
NSLog(@"Does nothing");
}
- (void) fooOneInput:(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:);

您的代码有两个问题。一个已经确认并回答了,但另一个没有。第一个问题是您的选择器缺少其参数的名称。但是,即使修复了这个问题,该行仍然会引发异常,前提是修改后的方法签名仍然包含多个参数。假设修改后的方法声明为:

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

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

您总是可以重新定义您的方法来接受一个集合,因为它是唯一的参数:

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

然而,有一个更优雅的解决方案(不需要重构)。答案是使用 NSInvation 及其 setArgument:atIndex:invoke方法。

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

祝你好运!

@ Shane Arney

performSelector:withObject:withObject:

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

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

IOS 用户还期望自动大写: 在标准文本字段中, 在区分大小写的语言中,句子的第一个字母是 自动资本化。

您可以决定是否实现这些特性; 没有 为刚才列出的任何特性提供专用的 API,因此提供它们 是一种竞争优势。

苹果公司的文件说,在定制键盘上没有可用于这个功能和其他一些预期功能的 API。所以你需要找到你自己的逻辑来实现它。

发表于2021 _ 10 _ 15,由一个 Android 开发者。

(OC 更难使用,-_-| |)

用多个参数调用选择器,

你可以用 NSObject performSelector:withObject:withObject,

但只支持通过两个论点! ! !

幸运的是,您可以通过 objc_msgSend函数实现 performSelector withObject X 3

#include <objc/message.h>


- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 withObject:(id)object3 {
typedef id (*send_type)(id, SEL, id, id, id);
send_type func = (send_type) objc_msgSend;
id retValue = func(self, aSelector, object1, object2, object3);
return retValue;
}

用法:

- (NSString *)ObjcMsgSendWithString:(NSString *)string withNum:(NSNumber *)number withArray:(NSArray *)array {
NSLog(@" ---> %@, %@, %@", string, number, array[0]);
return @"return 311";
}


- (void)test{
NSString *str = @"字符串objc_msgSend";
NSNumber *num = @20;
NSArray *arr = @[@"数组值1", @"数组值2"];


SEL sel = @selector(ObjcMsgSendWithString:withNum:withArray:);
NSLog(@"1223 ---> %@", [self performSelector:sel withObject:str withObject:num withObject:arr]);
}