how to call a method of multiple arguments with delay
Solution 1
use dispatch_after:
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//code to be executed on the main queue after delay
[self MoveSomethingFrom:from To:to];
});
EDIT 2015: For Swift, i recommend using this small helper method: dispatch_after - GCD in swift?
Solution 2
You can also implement method in NSObject's category using NSInvocation object (works in all versions of iOS). I guess it should be something like this:
@interface NSObject(DelayedPerform)
- (void)performSelector:(SEL)aSelector withObject:(id)argument0 withObject:(id)argument1 afterDelay:(NSTimeInterval)delay {
NSMethodSignature *signature = [self methodSignatureForSelector:aSelector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:self];
[invocation setSelector:aSelector];
[invocation setArgument:&argument0 atIndex:2];
[invocation setArgument:&argument1 atIndex:3];
[invocation performSelector:@selector(invoke) withObject:nil afterDelay:delay];
}
@end
Solution 3
Other ideas:
1) You could use NSInvocations:
+ (NSInvocation *)invocationWithMethodSignature:(NSMethodSignature *)signature
(>> see Eldar Markov's answer)
Documentation:
https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/Reference/Reference.html
2) You could use a helper method..
[self performSelector:@selector(helperMethod) withObject:nil afterDelay:delay];
- (void) helperMethod
{
// of course x1 and x2 have to be safed somewhere else
[object moveSomethigFrom: x1 to: x2];
}
3) You could use an array or a dictionary as parameter..
NSArray* array = [NSArray arrayWithObjects: x1, x2, nil];
[self performSelector:@selector(handleArray:) withObject:array afterDelay:delay];
- (void) handleArray: (NSArray*) array
{
[object moveSomethigFrom: [array objectAtIndex: 0] to: [array objectAtIndex: 1]];
}
Solution 4
Swift:
let delayInSeconds = 3.0;
let delay = delayInSeconds * Double(NSEC_PER_SEC)
let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay));
dispatch_after(popTime, dispatch_get_main_queue(), {
// DO SOMETHING AFTER 3 sec
});
Solution 5
Here is how you can trigger a block after a delay in Swift:
runThisAfterDelay(seconds: 5) { () -> () in
print("Prints this 5 seconds later in main queue")
//Or perform your selector here
}
/// EZSwiftExtensions
func runThisAfterDelay(seconds seconds: Double, after: () -> ()) {
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue(), after)
}
The argument count does not really matter.
Its included as a standard function in my repo: https://github.com/goktugyil/EZSwiftExtensions
Frade
Updated on December 02, 2020Comments
-
Frade over 3 years
I'm trying to call a method after some delay.
I know there is a solution for that:
[self performSelector:@selector(myMethod) withObject:nil afterDelay:delay];
I saw this question and Documentation
But my question is: How can I call a method that takes two parameters??
for instance:
- (void) MoveSomethigFrom:(id)from To:(id)to;
How would I call this method with delay, using
performSelector:withObject:afterDelay:
Thanks
-
Alexander about 12 yearsEither that, or you can put as many parameters as you want in a container and send it as an argument for the
performSelector: withObject: afterDelay
method. -
Eldar Markov about 12 yearsyou can use it in >= 3.2 as well. I just wanted to show that it's not necessary to use GCD. I'll edit my original answer)
-
Frade about 12 yearsOk.. I'm sorry but, what is GCD? what's the problem using it?
-
Frade about 12 yearsI'm asking, because I have three answers and the 3 are good. Just trying to understand which is the best one to use. Thanks
-
Eldar Markov about 12 yearsGCD - it's Grand Central Dispatch. Part of iOS sdk 4.0 and higher.If you want to use it in all versions of iOS use mine version)
-
Frade about 12 yearsThis seems a good approach, it really delays the call. But it happens something strange, the method doesn't do what is expected, does something else, that I can't even understand..
-
Frade about 12 yearsgot it.. It was some code that was executed during the delay.. thanks
-
Martin Ullrich about 12 yearsYes if you really want to deploy on devices < 4.0 you have to stay away from GCD. But developing for iOS 4+ is safe as over 90% of active devices are running it and testing/coding effort is heavily reduced (assuming that you do serious testing)
-
Martin Ullrich about 12 yearsadditionally, GCD improves code readability because because you don't have to have lots of methods being called asynchronously (you "just" have to get used to ^{}-Notations)
-
ArtOfWarfare almost 11 yearsAs a suggestion, don't reference other answers on SO as being "above" or "below", as they can be sorted more ways than one, and that most people sort by rating, which can be volatile. I suggest hitting the "share" button beneath the answer and sharing a link to it, for incase a question ends up with a large number of answers.
-
vir us over 9 yearsis there a way to cancel scheduled call?
-
vir us over 9 yearsif someone is interested this should work to cancel scheduled call (if performSelector:withObject:afterDelay: was used): [NSObject cancelPreviousPerformRequestsWithTarget:yourTarget selector:aSelector object: anArgument];
-
Martin Ullrich about 8 years@iEngineer: Sure u got everything right? i once used "MSEC_PER_SEC" instead of "NSEC_PER_SEC" which is 10^6 times faster.