171

Is there an easy way delay a method call for 1 second?

I have a UIImageView that reacts on a touch event. When the touch is detected, some animations happen in the app. After one second, I want to call another method. In this case, I can't use the animationDidStop selector.

TheNeil
  • 3,321
  • 2
  • 27
  • 52
Thanks
  • 40,109
  • 71
  • 208
  • 322
  • There are certainly several ways to do that, one of them might be to simply use sleep() to suspend the program/thread for a number of milliseconds, **however** I think you might want to tell us what exactly you're trying to accomplish by doing that? I mean, what is your actual problem? The idea of delaying a method call seems like a 'solution' to be, one that doesn't sound too good to be honest. So, just tell us more about the scenario you have in mind. – none May 28 '09 at 12:54

11 Answers11

258
performSelector:withObject:afterDelay:

Document Reference

Lucas Gabriel Sánchez
  • 40,116
  • 20
  • 56
  • 83
Jim
  • 4,691
  • 1
  • 25
  • 23
  • 7
    This is the correct answer. Please see http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/performSelector:withObject:afterDelay: – harms May 28 '09 at 13:06
  • Is there any way to something with the return value of the method that gets called? Or do I need to set it up to modify the parameter if I want to get some information back from it? – Gordon Gustafson Aug 07 '13 at 21:06
  • 1
    if someone is interested how to cancel scheduled call: [NSObject cancelPreviousPerformRequestsWithTarget:yourTarget selector:aSelector object: anArgument]; – vir us Aug 27 '14 at 21:14
203

You could also use a block

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    [object method]; 
});

Most of time you will want to use dispatch_get_main_queue, although if there is no UI in the method you could use a global queue.

Edit:

Swift 3 version:

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    object.method()
}

Equally, DispatchQueue.global().asyncAfter(... might also be a good option.

mcfedr
  • 7,845
  • 3
  • 31
  • 27
132

Best way to do is :

[self performSelector:@selector(YourFunctionName) 
           withObject:(can be Self or Object from other Classes) 
           afterDelay:(Time Of Delay)];

you can also pass nil as withObject parameter.

example :

[self performSelector:@selector(subscribe) withObject:self afterDelay:3.0 ];
Alex Cio
  • 6,014
  • 5
  • 44
  • 74
Milianoo
  • 1,476
  • 1
  • 10
  • 9
23

There are already a lot of answers and they are all correct. In case you want to use the dispatch_after you should be looking for the snippet which is included inside the Code Snippet Library at the right bottom (where you can select the UI elements).

enter image description here

So you just need to call this snippet by writing dispatch in code:

enter image description here

Alex Cio
  • 6,014
  • 5
  • 44
  • 74
16

You can use the perform selector for after the 0.1 sec delay method is call for that following code to do this.

[self performSelector:@selector(InsertView)  withObject:nil afterDelay:0.1]; 
Nimit Parekh
  • 16,776
  • 8
  • 50
  • 72
9

You can also:

[UIView animateWithDuration:1.0
                 animations:^{ self.view.alpha = 1.1; /* Some fake chages */ }
                 completion:^(BOOL finished)
{
    NSLog(@"A second lapsed.");
}];

This case you have to fake some changes to some view to get the animation work. It is hacky indeed, but I love the block based stuff. Or wrap up @mcfedr answer below.


waitFor(1.0, ^
{
    NSLog(@"A second lapsed");
});

typedef void (^WaitCompletionBlock)();
void waitFor(NSTimeInterval duration, WaitCompletionBlock completion)
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, duration * NSEC_PER_SEC),
                   dispatch_get_main_queue(), ^
    { completion(); });
}
Geri Borbás
  • 15,810
  • 18
  • 109
  • 172
  • Not sure, but I think the first option you suggest may have side-effects that users should be aware of, eg blocking user interaction on parts of the UI. My instinct is that it would also cause some unnecessary CPU or other resource drain, but I haven't checked. – Bjorn Roche Jun 03 '16 at 20:19
8

You can do this

[self performSelector:@selector(MethodToExecute) withObject:nil afterDelay:1.0 ];
Nitesh
  • 1,389
  • 1
  • 15
  • 24
6

Swift 2.x

let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
 dispatch_after(delayTime, dispatch_get_main_queue()) {
 print("do some work")
}

Swift 3.x --&-- Swift 4

DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
    print("do some work")
}

or pass a escaping closure

func delay(seconds: Double, completion: @escaping()-> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + seconds, execute: completion)
}
Daksh Gargas
  • 3,498
  • 2
  • 23
  • 37
Salman Ghumsani
  • 3,647
  • 2
  • 21
  • 34
1

There is a Swift 3 solution from the checked solution :

self.perform(#selector(self.targetMethod), with: self, afterDelay: 1.0)

And there is the method

@objc fileprivate func targetMethod(){

}
Kevin ABRIOUX
  • 16,507
  • 12
  • 93
  • 99
0

Use in Swift 3

perform(<Selector>, with: <object>, afterDelay: <Time in Seconds>)
-35

NOTE: this will pause your whole thread, not just the one method.
Make a call to sleep/wait/halt for 1000 ms just before calling your method?

Sleep(1000); // does nothing the next 1000 mSek

Methodcall(params); // now do the real thing

Edit: The above answer applies to the general question "How can I delay a method call for 1 second?", which was the question asked at the time of the answer (infact the answer was given within 7 minutes of the original question :-)). No Info was given about the language at that time, so kindly stop bitching about the proper way of using sleep i XCode og the lack of classes...

Albert Renshaw
  • 17,282
  • 18
  • 107
  • 195
Tom Arleth
  • 153
  • 1
  • 3
  • Only in the current thread, other threads will continue to run. – Marc Charbonneau May 28 '09 at 13:13
  • 5
    Geez. I get why this was down-voted a few times, but who the heck saw this at -27 and decided it needed another? Does -3 or something not get the point across. Why not just edit the answer to say "this will pause your whole thread" or something instead of downvoting it people? – Albert Renshaw Sep 20 '15 at 06:25
  • So what if you just want to pause the whole thread? Seems like a valid option if it comes with a decent warning. – Lucas van Dongen Aug 12 '16 at 18:39
  • @AlbertRenshaw I totally agree with you. I am here and its 35 downs and I given him my up. I see more like attacking towards the low reputed users so badly. No one will do any edit or specify anything. I've seen one answer today that the got really drowned. The only mistake that person did that is he/she answered under a swift question with objective c language. If it is a huge mistake, I want to show so many swift answers under objective c questions. – Soorej Babu Jan 02 '20 at 08:41