简体   繁体   English

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

[英]Objective-C: Calling selectors with multiple arguments

In MyClass.m, I've defined在 MyClass.m 中,我定义了

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

and the appropriate declaration in MyClass.h .以及 MyClass.h 中的适当声明。 Later I want to call后来我想打电话

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

in MyClass.m but I get an error similar to * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[MyClass myTest:withAtring:]: unrecognized selector sent to instance 0xe421f0'在 MyClass.m 中,但我收到类似于* 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序的错误,原因:“* -[MyClass myTest:withAtring:]: unrecognized selector sent to instance 0xe421f0”

I tried a simpler case with a selector that took no arguments that printed a string to console and that worked just fine.我尝试了一个更简单的案例,使用一个选择器,它不带任何参数,将字符串打印到控制台,并且工作得很好。 What's wrong with the code and how can I fix it?代码有什么问题,我该如何解决? Thanks.谢谢。

In Objective-C, a selector's signature consists of: 在Objective-C中,选择器的签名包括:

  1. The name of the method (in this case it would be 'myTest') (required) 方法的名称(在这种情况下,它将是'myTest')(必需)
  2. A ':' (colon) following the method name if the method has an input. 如果方法有输入,则在方法名后面加一个':'(冒号)。
  3. A name and ':' for every additional input. 每个附加输入的名称和“:”。

Selectors have no knowledge of: 选择者不知道:

  1. The input types 输入类型
  2. The method's return type. 方法的返回类型。

Here's a class implementation where performMethodsViaSelectors method performs the other class methods by way of selectors: 这是一个类实现,其中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

The method you want to create a selector for has a single input, so you would create a selector for it like so: 您要为其创建选择器的方法具有单个输入,因此您将为其创建一个选择器,如下所示:

SEL myTestSelector = @selector(myTest:);

Your method signature is: 您的方法签名是:

- (void) myTest:(NSString *)

withAString happens to be the parameter (the name is misleading, it looks like it is part of the selector's signature). withAString恰好是参数(名称具有误导性,看起来它是选择器签名的一部分)。

If you call the function in this manner: 如果以这种方式调用该函数:

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

It will work. 它会工作。

But, as the other posters have suggested, you may want to rename the method: 但是,正如其他海报所建议的那样,您可能想要重命名该方法:

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

And call: 并致电:

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

@Shane Arney @Shane Arney

performSelector:withObject:withObject:

You might also want to mention that this method is only for passing maximum 2 arguments, and it cannot be delayed. 您可能还想提一下,此方法仅用于传递最多2个参数,并且不能延迟。 (such as performSelector:withObject:afterDelay:) . (例如performSelector:withObject:afterDelay:)

kinda weird that apple only supports 2 objects to be send and didnt make it more generic. 有点奇怪,苹果只支持2个对象发送,并没有使它更通用。

Your code has two problems. 您的代码有两个问题。 One was identified and answered, but the other wasn't. 一个被确认并回答,但另一个没有。 The first was that your selector was missing the name of its parameter. 第一个是你的选择器缺少其参数的名称。 However, even when you fix that, the line will still raise an exception, assuming your revised method signature still includes more than one argument. 但是,即使您修复了该行,该行仍将引发异常,假设您修改的方法签名仍包含多个参数。 Let's say your revised method is declared as: 假设您修改后的方法声明为:

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

Creating selectors for methods that take multiple arguments is perfectly valid (eg @selector(myTestWithString:comparedTo:) ). 为具有多个参数的方法创建选择器是完全有效的(例如@selector(myTestWithString:comparisonTo :))。 However, the performSelector method only allows you to pass one value to myTest, which unfortunately has more than one parameter. 但是,performSelector方法只允许您将一个值传递给myTest,不幸的是,myTest有多个参数。 It will error out and tell you that you didn't supply enough values. 它会报错并告诉您没有提供足够的值。

You could always redefine your method to take a collection as it's only parameter: 您可以随时重新定义您的方法以获取集合,因为它是唯一的参数:

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

However, there is a more elegant solution (that doesn't require refactoring). 但是,有一个更优雅的解决方案(不需要重构)。 The answer is to use NSInvocation, along with its setArgument:atIndex: and invoke methods. 答案是使用NSInvocation及其setArgument:atIndex:invoke方法。

I've written up an article, including a code example , if you want more details. 如果你想了解更多细节,我已经写了一篇文章,包括一个代码示例 The focus is on threading, but the basics still apply. 重点是线程,但基础仍然适用。

Good luck! 祝好运!

Your method signature makes no sense, are you sure it isn't a typo? 你的方法签名毫无意义,你确定它不是拼写错误吗? I'm not clear how it's even compiling, though perhaps you're getting warnings that you're ignoring? 我不清楚它是如何编译的,虽然你可能会收到警告你忽略了?

How many parameters do you expect this method to take? 您希望此方法采用多少个参数?

Think the class should be defined as: 认为该类应定义为:

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

You only have a single parameter so you should only have a single : 您只有一个参数,因此您应该只有一个参数:

You might want to consider using %@ in your NSLog also - it is just a good habit to get into - will then write out any object - not just strings. 您可能还想考虑在NSLog中使用%@ - 这只是一个很好的习惯 - 然后会写出任何对象 - 而不仅仅是字符串。

Post at 2021_10_15 by an android developer.一位安卓开发者在 2021_10_15 发帖。

(OC is harder to use, -_-||) (OC比较难用,-_-||)

Calling selectors with multiple arguments,使用多个参数调用选择器,

you can use NSObject performSelector:withObject:withObject ,你可以使用NSObject performSelector:withObject:withObject

but only support pass two arguments!!!但只支持传递两个参数!!!

Fortunately, you can implement you performSelector withObject X 3 by objc_msgSend function.幸运的是,您可以通过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;
}

Usage:用法:

- (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]);
}

iOS users also expect autocapitalization: In a standard text field, the first letter of a sentence in a case-sensitive language is automatically capitalized. iOS用户还期望自动资本化:在标准文本字段中,区分大小写的语句中的第一个字母会自动大写。

You can decide whether or not to implement such features; 您可以决定是否实施此类功能; there is no dedicated API for any of the features just listed, so providing them is a competitive advantage. 对于刚刚列出的任何功能,没有专用API,因此提供它们是一种竞争优势。

Apple document is saying there is no API available for this feature and some other expected feature in a customkeyboard. Apple文档称,此功能没有可用的API以及自定义键盘中的其他一些预期功能。 so you need to find out your own logic to implement this. 所以你需要找出自己的逻辑来实现它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM