iOS - 如何使用多个参数和 afterDelay 实现 performSelector



我是iOS新手。我有一个选择器方法如下 -

- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{
}

我正在尝试实现这样的事情 -

[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second" afterDelay:15.0];

但这给了我一个错误说——

Instance method -performSelector:withObject:withObject:afterDelay: not found

关于我错过了什么的任何想法?

就个人而言,我认为更能满足您需求的解决方案是使用 NSInvocation。

类似以下内容的内容将完成这项工作:

indexPath dataSource 是在同一方法中定义的两个实例变量。

SEL aSelector = NSSelectorFromString(@"dropDownSelectedRow:withDataSource:");
if([dropDownDelegate respondsToSelector:aSelector]) {
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[dropDownDelegate methodSignatureForSelector:aSelector]];
    [inv setSelector:aSelector];
    [inv setTarget:dropDownDelegate];
    [inv setArgument:&(indexPath) atIndex:2]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
    [inv setArgument:&(dataSource) atIndex:3]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
    [inv invoke];
}

因为没有[NSObject performSelector:withObject:withObject:afterDelay:]方法这样的东西。

您需要将要发送的数据封装到某个单个目标C对象(例如NSArray,NSDictionary,一些自定义Objective C类型(中,然后通过众所周知和喜爱的[NSObject performSelector:withObject:afterDelay:]方法传递它。

例如:

NSArray * arrayOfThingsIWantToPassAlong = 
    [NSArray arrayWithObjects: @"first", @"second", nil];
[self performSelector:@selector(fooFirstInput:) 
           withObject:arrayOfThingsIWantToPassAlong  
           afterDelay:15.0];

您可以将参数打包到一个对象中,并使用帮助程序方法来调用原始方法,正如 Michael 和其他人现在所建议的那样。

另一种选择是dispatch_after,它将获取一个块并在特定时间将其排队。

double delayInSeconds = 15.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [self fooFirstInput:first secondInput:second];
});

或者,正如您已经发现的那样,如果您不需要延迟,则可以使用- performSelector:withObject:withObject:

最简单的

选择是修改方法,使其采用包含两个参数的单个参数,例如NSArrayNSDictionary(或添加第二个方法,该方法采用单个参数,解压缩它,并调用第一个方法,然后在延迟时调用第二个方法(。

例如,你可以有这样的东西:

- (void) fooOneInput:(NSDictionary*) params {
    NSString* param1 = [params objectForKey:@"firstParam"];
    NSString* param2 = [params objectForKey:@"secondParam"];
    [self fooFirstInput:param1 secondInput:param2];
}

然后要调用它,您可以执行以下操作:

[self performSelector:@selector(fooOneInput:) 
      withObject:[NSDictionary dictionaryWithObjectsAndKeys: @"first", @"firstParam", @"second", @"secondParam", nil] 
      afterDelay:15.0];
- (void) callFooWithArray: (NSArray *) inputArray
{
    [self fooFirstInput: [inputArray objectAtIndex:0] secondInput: [inputArray objectAtIndex:1]];
}

- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second
{
}

并调用它:

[self performSelector:@selector(callFooWithArray) withObject:[NSArray arrayWithObjects:@"first", @"second", nil] afterDelay:15.0];

您可以在此处找到提供的所有类型的 performSelector: 方法:

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html

有很多变体,但没有一个版本需要多个对象和延迟。你需要把你的论点包装在NSArray或NSDictionary中。

- performSelector:
- performSelector:withObject:
- performSelector:withObject:withObject:
– performSelector:withObject:afterDelay:
– performSelector:withObject:afterDelay:inModes:
– performSelectorOnMainThread:withObject:waitUntilDone:
– performSelectorOnMainThread:withObject:waitUntilDone:modes:
– performSelector:onThread:withObject:waitUntilDone:
– performSelector:onThread:withObject:waitUntilDone:modes:
– performSelectorInBackground:withObject: 

我不喜欢NSInvocation的方式,太复杂了。让我们保持简单和干净:

// Assume we have these variables
id target, SEL aSelector, id parameter1, id parameter2;
// Get the method IMP, method is a function pointer here.
id (*method)(id, SEL, id, id) = (void *)[target methodForSelector:aSelector];
// IMP is just a C function, so we can call it directly.
id returnValue = method(target, aSelector, parameter1, parameter2);

我只是做了一些滑动,需要调用原始方法。我所做的是制定一个协议并将我的对象投射到它上面。另一种方法是在类别中定义方法,但需要禁止显示警告(#pragma clang 诊断忽略"-Wincomplete-implementation"(。

一种简单且可重用的方法是扩展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; //0 and 1 reserved
    for (NSObject *argument in arguments) {
        [invocation setArgument: &argument atIndex: index];
        index ++;
    }
    [invocation invokeWithTarget: self];
}

我只会创建一个自定义对象,将所有参数作为属性,然后将该单个对象用作参数

对于单个参数

perform(#selector(fuctionOne(_:)), with: arg1, afterDelay: 2)
@objc func fuctionOne(_ arg1: NSUserActivity) {
    // Do Something
}

对于多个参数

perform(#selector(fuctionTwo(_:_:)), with: [arg1, arg2], afterDelay: 2)
@objc func fuctionTwo(_ arg1: URL, _ arg2: [UIApplication.OpenURLOptionsKey: Any] = [:]) {
    // Do Something
}

最新更新