I want to call any method OR event after 5 second in iphone without using NStimer.
Use performSelector:withObject:afterDelay: method.
[self performSelector:#selector(methodName) withObject:nil afterDelay:5];
Or use GCD:
double delayInSeconds = 5.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
/* code to be executed on the main queue after delay */
});
The question sounds like a very pointless assignment. That calls for an equally useless answer:
sleep(5);
[self myMethodToCallAfter5Seconds];
Edit: Since people don't seem to like my answer, here are some thoughts:
The OP asked for a way to send a message after a delay. He explicitly asked for a way to do this without using an NSTimer yet he didn't specify why. As there are many ways to send a message after a delay, picking one depends upon the reason why to avoid any specific method. Not knowing the reason for refusing an obvious approach there's only speculation.
One possible situation could be a background thread without a runloop that should await the delay. Here my (not totally serious) proposal could even be a proper solution when blocking the thread is not an issue. In this scenario neither NSTimer nor performSelector:withObject:afterDelay: could be used.
I added this answer to highlight the fact that the question makes little sense without giving a reason. As my answer fulfills the specification it shows the pointlessness of the question.
Related
In iOS env, is it possible to make current thread sleep for seconds, then execute my code? NSTimer, GDC or any technique is okay for me.
It would be better if you shared what you have done but it here you go.
There are a few options you can go with:
Option 1
// Standard Unix calls
sleep();
usleep();
Some documentation regarding the sleep function can be found here. You'll find that they are actually C functions but since Objective-C is a strict superset of C we can still use the sleep and usleep functions.
Option 2
[NSThread sleepForTimeInterval:2.000];//2 seconds
The Apple documentation for this method states:
Sleeps the thread for a given time interval.
Discussion
No run loop processing occurs while the thread is blocked.
Option 3
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
1 * NSEC_PER_SEC),
dispatch_get_main_queue(),
^{
// Do whatever you want here.
});
The Grand Central Dispatch route is a pretty good way of doing things as well. Here is the Apple Documentation for Grand Central Dispatch which is quite a good read.
There is also this question that might be pretty useful How to Wait in Objective-C
it cannot be easier.
sleep(seconds);
Use the class method + (void)sleepForTimeInterval:(NSTimeInterval)ti
The variable NSTimeInterval is of type double and represents the number of seconds to sleep
// Block for .5 seconds
[NSThread sleepForTimeInterval:.5];
Either
[self performSelector:#selector(YourFunctionName) withObject:(can be Self or Object from other Classes) afterDelay:(Time Of Delay)];`
or
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC),
dispatch_get_main_queue(), ^{
//your method
});
it depends how you are creating (spawning) your threads. For example if you are creating your thread with NSThread class, you can use the two class methods :
sleepUntilDate:
sleepForTimeInterval:
But generally it's a bad idea to handle the threading management yourself, because multithreading programming is very hard. You can use GCD or operations queues for example to handle the multithreading in your application.
I'm setting a timer so that after a second passes I reset a value for my keyboard extension. The problem is that I feel like the following call is stalling my UI:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self resetDoubleTapBool];
})
Is there an asynchronous way of doing this, or a better way in general? Thanks!
The dispatch_after() call itself does not block. At (or shortly after) the appointed time, the block will be submitted to the main queue. Submitting it doesn't block the main thread. When the main thread next runs its run loop or is idle within dispatch_main(), it will execute the block.
IF your -resetDoubleTapBool method takes any appreciable amount of time, that can stall your UI. That's just the same as any code that runs on the main thread. It's not specific to dispatch_after() or any other part of GCD.
According to the function documentation:
This function waits until the specified time and then asynchronously adds block to the specified queue.
This question already has answers here:
Prevent dispatch_after() background task from being executed
(11 answers)
Closed 8 years ago.
Is there a way to cancel dispatch_after() scheduled for some time in future, and haven't fired so far?
I'm trying to make something like a scheduler for updates from server, and this method is just like I want, but, I'd love to cancel and re-schedule it at some point.
Is it possible at all or I have to fallback and use NSTimer?
There is NO way to prevent a dispatch_block from executing once it has been dispatch to it's queue, meaning that your dispatch_after cannot be canceled. Only option is to add in your block a condition to be checked at runtime to prevent execution.
ie.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC), dispatch_get_main_queue(), ^ {
if(self.shouldExecuteDispatchBlock)
{ // do your stuff } });
OK, so, with all answers collected, and possible solutions, seems like the best one for this case (preserving simplicity) is calling performSelector:withObject:afterDelay: and cancelling it with cancelPreviousPerformRequestsWithTarget: call when desired. In my case - just before scheduling next delayed call:
[NSObject cancelPreviousPerformRequestsWithTarget: self selector:#selector(myDelayedMethod) object: self];
[self performSelector:#selector(myDelayedMethod) withObject: self afterDelay: desiredDelay];
For this purpose i used this class:
https://github.com/SebastienThiebaud/dispatch_cancelable_block
you can call a cancel() function to revoke the execution of what's in the block.
Use a dispatch timer source (that is what dispatch_after uses internally anyway).
A dispatch timer source can be canceled or its timer parameters changed after creation.
This code
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSLog(#"Main Thread? %d", [NSThread isMainThread]);
});
shows that I'm in the main thread. Even doing this:
queue = dispatch_queue_create("nonMainQueue", NULL);
still reports that I'm in the main queue. This is, it seems, because I'm using dispatch sync.
Does this mean that my code is the same as not using dispatch_sync at all? Also: what's the point of dispatch_sync if it does nothing at all, then?
Because queues are not threads, in order to check if you are on the main 'queue', you must use different code, something similar to this:
if (dispatch_get_current_queue() == dispatch_get_main_queue()) {
NSLog(#"On Main Thread!");
}
Just note that dispatch_get_current_queue is deprecated, and is subject to be completely removed in a later iOS/Mac OS version.
This is documented behavior. As an optimization the blocks passed to dispatch_sync are executed on the current thread if possible (which is almost always).
My understanding from Apple's GCD guide, there is no guarantee that dispatch queues will execute on a separate thread. GCD will determine which thread, and if necessary create a new one.
Part of the point is now you do not have to think about threads.
The only thing to keep in mind, is to make sure you are updating UI elements on the main queue, for example:
// on background queue
dispatch_async( dispatch_get_main_queue(), ^(void){
someLabel.text = #"My Text";
});
I'm executing some code within some NSOperation objects managed by an NSOperationQueue. The code also contains a delayed method call using performSelector:withObject:afterDelay:.
The problem is, that the corresponding selector which should be called delayed, is not called at all.
Having read this answer to a StackOverflow question, I guess it's due to the fact that the NSOperation already has finished and its thread doesn't even exist anymore, "forgetting" the scheduled call to the selector.
How can I work around this?
How can I do a delayed call to a method within an NSOperation?
One possibility would be to use Grand Central Dispatch, namely dispatch_after():
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_after(popTime, queue, ^{
...
});
Instead of dispatch_get_global_queue(), you can of course also create your own dispatch queue or use the main queue with dispatch_get_main_queue().