Reputation: 2988
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
Upvotes: 39
Views: 36721
Reputation: 39201
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
Upvotes: 1
Reputation: 100701
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?
Upvotes: 114
Reputation: 8397
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
});
Upvotes: 2
Reputation: 1542
These will all work, but are all much more complex than is needed.
Design the method to be called with an NSDictionary argument. Put the objects in it you need.
If you want the method to be accessible by other means as well, call instead a method that 'unwraps' the dictionary and calls the intended method with explicit parameters.
Upvotes: 0
Reputation: 9977
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]];
}
Upvotes: 6
Reputation: 950
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
Upvotes: 7