iOS - 如何实现具有多个参数和 afterDelay 的 performSelector?

Posted

技术标签:

【中文标题】iOS - 如何实现具有多个参数和 afterDelay 的 performSelector?【英文标题】:iOS - How to implement a performSelector with multiple arguments and with afterDelay? 【发布时间】:2012-01-16 08:46:13 【问题描述】:

我是 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

关于我缺少什么的任何想法?

【问题讨论】:

【参考方案1】:

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

类似下面的东西可以完成这项工作:

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

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];

【讨论】:

同意。应该是正确答案。非常有用的解决方案。特别是在我的情况下,不允许更改包含多个参数的方法的签名。 这看起来是一个很好的解决方案。有没有办法从使用这种技术调用的方法中获取返回值? 你如何使用这种技术指定延迟? @death_au,而不是 invoke,请致电:[inv performSelector:@selector(invoke) withObject:nil afterDelay:1]; 我必须同意这是一个很好的解决方案。祝大家编码愉快! 谈话有点晚了,但有一个问题。什么是 dropDownDelegate?【参考方案2】:

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

您需要将要发送的数据封装到某个单一的Objective 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];

【讨论】:

如果我删除 afterDelay 参数,我不会收到错误消息。这是否意味着 afterDelay 不允许与多个参数一起使用? 您不会收到错误消息,但我敢打赌您会在运行时收到“未找到选择器”异常(并且您尝试执行的操作不会被调用) ...试试看。 :-) 这里如何传递 Bool 类型? 使它成为一个 Objective C 风格的对象(例如“NSNumber * whatToDoNumber = [NSNumber numberWithBool: doThis];”)并将它作为一个参数传递,@virata。 这是一个单独的问题@Raj ...请单独发布。【参考方案3】:

您可以将参数打包到一个对象中,并使用辅助方法来调用您的原始方法,正如 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:

【讨论】:

这种方法的另一个好处是你可以使用__weak 给你的假定时器一个返回自我的弱链接——这样你就不会人为地延长对象的生命周期,例如如果您的 performSelector:afterDelay: 效果有点像尾递归(尽管没有递归),那么它会解决保留周期。 是的,这应该是公认的答案。它更合适,更直接。【参考方案4】:

最简单的选择是修改您的方法以采用包含两个参数的单个参数,例如 NSArrayNSDictionary(或添加第二个采用单个参数的方法,解包并调用第一个方法,然后延迟调用 second 方法)。

例如,你可以有类似的东西:

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

【讨论】:

如果方法不能修改怎么办,比如说它存在于 UIKit 中或其他什么地方?不仅如此,将方法更改为使用NSDictionary 也会失去类型安全性。不理想。 @fatuhoku - 括号中的内容; “添加第二种方法,该方法采用单个参数,解包并调用第一种方法”。 不管第一种方法在哪里都有效。至于类型安全,在决定使用performSelector:(或NSInvocation)的那一刻就丢失了。如果这是一个问题,最好的选择可能是通过 GCD。【参考方案5】:
- (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];

【讨论】:

【参考方案6】:

你可以在这里找到所有提供的 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: 

【讨论】:

【参考方案7】:

我不喜欢 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);

【讨论】:

不错!用“目标”替换“vc”【参考方案8】:

我只是做了一些调整,需要调用原始方法。我所做的是制定一个协议并将我的对象投射到它上面。 另一种方法是在类别中定义方法,但需要抑制警告(#pragma clang diagnostic ignored "-Wincomplete-implementation")。

【讨论】:

【参考方案9】:

一个简单且可重用的方法是扩展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];

【讨论】:

【参考方案10】:

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

【讨论】:

以上是关于iOS - 如何实现具有多个参数和 afterDelay 的 performSelector?的主要内容,如果未能解决你的问题,请参考以下文章

Apiary.io - 具有不同参数的多个响应(200)

如何将 Objective-C initXXX 方法绑定到具有相同类型参数的 Xamarin.iOS 构造函数?

如何将 select 语句的 IN 子句中的参数作为具有多个值的参数传递?

如何让 perl 正确传递具有多个参数和复杂文件路径(空格和符号)的命令行参数?

ios如何定义函数时可以传一个参数或多个参数或不传 我记得有个变量名加到函数名后边就能实现这个效果 不

具有多个可选参数的控制台输出