Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS - How to implement a performSelector with multiple arguments and with afterDelay?

I am an iOS newbie. I have a selector method as follows -

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

}

I am trying to implement something like this -

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

But that gives me an error saying -

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

Any ideas as to what I am missing?

like image 266
Suchi Avatar asked Dec 08 '11 23:12

Suchi


4 Answers

Personally, I think that a closer solution to your needs is the use of NSInvocation.

Something like the following will do the work:

indexPath and dataSource are two instance variables defined in the same method.

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];
}
like image 54
valvoline Avatar answered Nov 07 '22 20:11

valvoline


Because there is no such thing as a [NSObject performSelector:withObject:withObject:afterDelay:] method.

You need to encapsulate the data you want to send along into some single Objective C object (e.g. a NSArray, a NSDictionary, some custom Objective C type) and then pass it through the[NSObject performSelector:withObject:afterDelay:] method that is well known and loved.

For example:

NSArray * arrayOfThingsIWantToPassAlong = 
    [NSArray arrayWithObjects: @"first", @"second", nil];

[self performSelector:@selector(fooFirstInput:) 
           withObject:arrayOfThingsIWantToPassAlong  
           afterDelay:15.0];
like image 20
Michael Dautermann Avatar answered Nov 07 '22 18:11

Michael Dautermann


You can package your parameters into one object and use a helper method to call your original method as Michael, and others now, have suggested.

Another option is dispatch_after, which will take a block and enqueue it at a certain time.

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

});

Or, as you've already discovered, if you don't require the delay you can just use - performSelector:withObject:withObject:

like image 34
Firoze Lafeer Avatar answered Nov 07 '22 18:11

Firoze Lafeer


The simplest option is to modify your method to take a single parameter containing both arguments, such as an NSArray or NSDictionary (or add a second method that takes a single parameter, unpacks it, and calls the first method, and then call the second method on a delay).

For instance, you could have something like:

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

And then to call it, you can do:

[self performSelector:@selector(fooOneInput:) 
      withObject:[NSDictionary dictionaryWithObjectsAndKeys: @"first", @"firstParam", @"second", @"secondParam", nil] 
      afterDelay:15.0];
like image 7
aroth Avatar answered Nov 07 '22 18:11

aroth