@selector - 带有多个参数的用法?

27
我今天第一次使用@selector,但是我还没有想出如何完成以下操作。如果有多个参数,您会如何编写@selector

没有参数:


没有参数:

-(void)printText {
    NSLog(@"Fish");
}

[self performSelector:@selector(printText) withObject:nil afterDelay:0.25];

单个参数:

-(void)printText:(NSString *)myText {
    NSLog(@"Text = %@", myText);
}

[self performSelector:@selector(printText:) withObject:@"Cake" afterDelay:0.25];

两个参数:

-(void)printText:(NSString *)myText andMore:(NSString *)extraText {
    NSLog(@"Text = %@ and %@", myText, extraText);
}

[self performSelector:@selector(printText:andMore:) withObject:@"Cake" withObject:@"Chips"];

多参数:(即超过2个)

NSInvocation


已更新以反映答案,感谢所有的帮助,非常感激。 - fuzzygoat
1
你的“双重参数”没有延迟。 - user102008
9个回答

40

 

 - (id)performSelector:(SEL)aSelector
           withObject:(id)anObject  
           withObject:(id)anotherObject

根据文档

这个方法与performSelector:相同,但是您可以为aSelector提供两个参数。 aSelector应该标识出可以接受两个类型为id的参数的方法。对于具有其他参数类型和返回值的方法,请使用NSInvocation

因此在您的情况下,您将使用:

[self performSelector:@selector(printText:andMore:)
           withObject:@"Cake"
           withObject:@"More Cake"]

19

如果你有两个以上的参数,在使用NSInvocation时可以使用NSObject的-methodForSelector:作为替代方案,例如:

SEL a_selector = ...
Type1 obj1 = ...
Type2 obj2 = ...
Type3 obj3 = ...
typedef void (*MethodType)(id, SEL, Type1, Type2, Type3);
MethodType methodToCall;
methodToCall = (MethodType)[target methodForSelector:a_selector];
methodToCall(target, a_selector, obj1, obj_of_type2, obj_of_type3);

1
这正是我一直在寻找的。我需要能够通过引用传递参数,但无法使用performSelector弄清楚如何做到这一点。我确实通过NSInvocation弄清楚了,但一直出现malloc错误。这正是我需要的。 - Nick Cipollina

14
我曾经遇到一个问题,需要在我的@ selector方法中使用afterDelay并传递多个参数。解决方案是什么?使用包装函数!
假设以下函数是我想要传递给@ selector的函数:
-(void)myFunct:(NSString *)arg1 andArg:(NSString *)arg2 andYetAnotherArg:(NSString *)arg3;

显然,在这里我甚至无法使用withObject: withObject:,所以需要写一个包装器!

-(void)myFunctWrapper:(NSArray *)myArgs {
    [self myFunct:[myArgs objectAtIndex:0] andArg:[myArgs objectAtIndex:1] andYetAnotherArg:[myArgs objectAtIndex:2]];
}

然后通过以下方式使用它:

NSArray *argArray = [NSArray arrayWithObjects:string1,string2,string3,nil];
[self performSelector:@selector(myFunctWrapper:) withObject:argArray afterDelay:1.0];

通过这种方式,我可以拥有多个参数并且可以延迟使用选择器。


1
你所称之为函数的东西实际上被称为方法。不仅在Objective-C中,而且在所有严肃的编程语言中都有这种区别。准确地说:只要这个东西附加到一个对象上,它就是一个方法。如果它独立存在,那么它被称为函数。 - Jacque
通常情况下,我倾向于使用字典来传递参数。这样不会受到顺序的影响,而且可以轻松地添加可选参数等。 - Hot Licks

4
@selector(printText:andMore:)

4
谢谢,但我该如何指定参数@"Cake"和@"More Cake"? - fuzzygoat

4

另一个选项是使用更简短的语法:

#import <objc/message.h> // objc_msgSend
...
((void (*)(id, SEL, Type1, Type2, Type3))objc_msgSend)(target, a_selector, obj1, obj_of_type2, obj_of_type3);

3
[self performSelector:@selector(printText:andMore) withObject:@"Cake" withObject:@"More Cake"];

1
-performSelector:withObject:withObject:-performSelector:withObject:afterDelay:,但两者的混合不存在。 - kennytm
没错,我在复制粘贴时犯了一个错误。你发现得很好。 - pheelicks

2

Ben-Uri的回答的基础上进行阐述,这个方法可以更加简洁地编写。

例如,调用UIView方法- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view可以按照以下方式进行:

SEL selector = @selector(covertPoint:toView:);
IMP method = [viewA methodForSelector:selector];
CGPoint pointInB = method(viewA, selector, pointInA, viewB);

根据这篇 Stack Overflow 帖子(https://dev59.com/6GTWa4cB1Zd3GeqPGcK4),如果启用了 ARC,以这种方式完成会导致内存问题。 - stuckj

1
如KennyTM所指出的,选择器语法是:
@selector(printText:andMore:)

你用这个调用它

performSelector:withObject:withObject. 

...如果你需要更多的参数或不同类型,你需要使用NSInvocation


1
使用NSInvocation,您可以创建一个实现的NSObject类别,如您所指定的。
- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments;

类似于:

- (void)performSelector:(SEL)aSelector withObjects:(NSArray *)arguments
{
    NSMethodSignature *signature = [self methodSignatureForSelector: aSelector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: signature];
    [invocation setSelector: aSelector];

    int index = 2; //
    for (NSObject *argument in arguments) {
        [invocation setArgument: &argument atIndex: index];
        index ++;
    }
    [invocation invokeWithTarget: self];
}

来自: iOS - 如何实现带有多个参数和延迟执行的performSelector?


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