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.
Related
How can I run a loop in the background such as:
while(1==1){
NSLog(#"hello");
}
while being able to detect a button click such as:
- (IBAction)button:(id)sender {
//do something
}
You can use GCD to run the code on a background thread.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
});
Read Apple's Concurrency Programming Guide and maybe Threading Programming Guide.
The first of these will introduce you to operation queues (NSOperation) and dispatch queues (GCD), the second to threads (NSThread & Posix).
If after reading the guide you are unsure which of the approaches to take, at least for the situation you raise above, consider GCD first and then operation queues.
If you get stuck implementing your solution ask a new question, showing your code and explaining your issues. Somebody will undoubtedly help you out.
HTH
In objective C,
I am making my program to wait using while loop
doInitialize()
{
dispach_group_t loadDataGroup=dispatch_group_create();
dispatch_group_async(loadDataGroup,...get_global_queue(..),0),^{
renewauth();
}
dispatch_group_notify(loadDataGroup,...get_global_queue(..),0),^{
//Do other tasks once renew session has completed...
}
}
renewauth()
{
RenewAuthTokenInProgress=true;
startRenewThread();
**while (RenewAuthTokenInProgress);**
}
In turn startRenewThread() function also performs dispatch_async operation inside. So I have to make renewAuth() wait.
And async task in startRenewThread will update the bool variable once renewal is successful.
Is there any better approach of doing it other than dispatch_groups?
And is it good to make other threads wait with while (true) statement?
Manoj Kumar,
using a while loop to wait till the boolean variable change is not the correct approach to solve the problem. Here are few of the issues with this method
Your CPU is un-necessarily burdened with checking the variable regularly.
This will clearly show that developer isn't much equipted with basic skills of coding and features available with language.
If for any reason your variable will never change then your CPU will never stop checking the value of bool in while loop and blocks the execution of further code on the same thread.
Here are few of the correct approach :
Blocks or closures : Make use of blocks to execute the code asynchronously when the RenewAuthToken is done.
Delegates : if blocks are harder to understand, Make use of delegates and trigger the delegate when you are done with RenewAuthToken.
Notifications : Add observer for notifications in classes which needs to respond when RenewAuthToken is done and throw notification from the asynctask and let the class to catch it execute the code.
Locks : If it is necessary to block the execution of the thread till the response comes use locks to control the thread execution rather than using while loop
EDIT
As pointed out by fogmeister in comments
If you block the main thread for too long with a while(true) loop then
the app will actually be terminated by the iOS Watchdog as it will
assume it has crashed
Please have a look at the link : understand iOS watchdog termination reasons provided by fogmeister
Hope it helps.
I believe what you need it's a semaphore like:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
__block BOOL done = FALSE;
while (true) {
[self someCompletionMethod completion:^(BOOL success) {
if(success) { // Stop condition
done = TRUE;
}
// do something
dispatch_semaphore_signal(sem); // This will let a new iteration
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
if(done) {
dispatch_async(dispatch_get_main_queue(), ^{
// Dispatch to main
NSLog(#"Done!");
break;
});
}
}
});
Semaphores are an old-school threading concept introduced to the world by the ever-so-humble Edsger W. Dijkstra. Semaphores are a complex topic because they build upon the intricacies of operating system functions.
You can see a tutorial here about semaphore and check it out more links: https://www.raywenderlich.com/63338/grand-central-dispatch-in-depth-part-2
I hope this can help you.
What you do is absolutely lethal. It blocks the running thread (presumably the main thread) so the UI is frozen. It runs one core at 100% load for no reason whatsoever which empties the battery rapidly and heats up the phone. This will get you some very, very unhappy customers or very, very happy ex-customers.
Anything like this has to run in the background: startRenewThread should trigger some action that sets RenewAuthTokenInProgress = NO and sets whether there is a new token or not, and then triggers further action.
This is an absolutely essential programming pattern on iOS (and Android as far as I know).
I've used both GCD and performSelectorOnMainThread:waitUntilDone in my apps, and tend to think of them as interchangeable--that is, performSelectorOnMainThread:waitUntilDone is an Obj-C wrapper to the GCD C syntax. I've been thinking of these two commands as equivalent:
dispatch_sync(dispatch_get_main_queue(), ^{ [self doit:YES]; });
[self performSelectorOnMainThread:#selector(doit:) withObject:YES waitUntilDone:YES];
Am I incorrect? That is, is there a difference of the performSelector* commands versus the GCD ones? I've read a lot of documentation on them, but have yet to see a definitive answer.
As Jacob points out, while they may appear the same, they are different things. In fact, there's a significant difference in the way that they handle sending actions to the main thread if you're already running on the main thread.
I ran into this recently, where I had a common method that sometimes was run from something on the main thread, sometimes not. In order to protect certain UI updates, I had been using -performSelectorOnMainThread: for them with no problems.
When I switched over to using dispatch_sync on the main queue, the application would deadlock whenever this method was run on the main queue. Reading the documentation on dispatch_sync, we see:
Calling this function and targeting
the current queue results in deadlock.
where for -performSelectorOnMainThread: we see
wait
A Boolean that specifies whether the
current thread blocks until after the
specified selector is performed on the
receiver on the main thread. Specify
YES to block this thread; otherwise,
specify NO to have this method return
immediately.
If the current thread is also the main
thread, and you specify YES for this
parameter, the message is delivered
and processed immediately.
I still prefer the elegance of GCD, the better compile-time checking it provides, and its greater flexibility regarding arguments, etc., so I made this little helper function to prevent deadlocks:
void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
}
Update: In response to Dave Dribin pointing out the caveats section ondispatch_get_current_queue(), I've changed to using [NSThread isMainThread] in the above code.
I then use
runOnMainQueueWithoutDeadlocking(^{
//Do stuff
});
to perform the actions I need to secure on the main thread, without worrying about what thread the original method was executed on.
performSelectorOnMainThread: does not use GCD to send messages to objects on the main thread.
Here's how the documentation says the method is implemented:
- (void) performSelectorOnMainThread:(SEL) selector withObject:(id) obj waitUntilDone:(BOOL) wait {
[[NSRunLoop mainRunLoop] performSelector:selector target:self withObject:obj order:1 modes: NSRunLoopCommonModes];
}
And on performSelector:target:withObject:order:modes:, the documentation states:
This method sets up a timer to perform the aSelector message on the current thread’s run loop at the start of the next run loop iteration. The timer is configured to run in the modes specified by the modes parameter. When the timer fires, the thread attempts to dequeue the message from the run loop and perform the selector. It succeeds if the run loop is running and in one of the specified modes; otherwise, the timer waits until the run loop is in one of those modes.
GCD's way is suppose to be more efficient and easier to handle and is only available in iOS4 onwards whereas performSelector is supported in the older and newer iOS.
On iOS device, I recently found that a strange behavior.
Code1:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"1111");
});
while (1) {
sleep(1);
}
});
Code2:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"1111");
});
while (1) {
sleep(0.5);
}
});
Code1 and Code2's only difference is that Code1 sleep 1second every loop and Code2 sleep 0.5.
If you run these two code on iOS device with single core, Code1 will print out the #"1111", but Code2 won't.
I don't why, the global queue is assumed to be concurrent.It should always print out the number no matter what other blocks are doing. And if it is something due to that single core device's limit, why sleep(0.5) and sleep(1) would make the difference?
I really want to know the reason for this.
EDIT
I found use sleep(0.5) is my stupid mistake. sleep() function take an unsigned int parameter.So sleep(0.5) is equal to sleep(0). But do sleep(0) will block the whole concurrent queue?
The reason is that your second sleep() is essentially a sleep(0) which means that you're now buzz-looping the thread that GCD gave to you, and that's probably the same thread that would have executed the nested dispatch_async() if you had given it a chance to do anything else, which the first example does. During the one second sleep, GCD sees that the thread is blocked and creates a new one to service the outstanding queued request(s). In the second example, you're essentially computationally starving the enqueued work - GCD is not smart enough to know that a thread has been locked into an infinite loop, and you're not giving the system enough work to justify (in GCD's eyes) the creation of another thread, so... You've essentially discovered a bug in GCD's low-threshold of work logic, I think.
Just checked out, 1st and 2nd snippets print "1111".
Note, nesting of dispatch_async you use won't give any profit, because you set the same priorities (DISPATCH_QUEUE_PRIORITY_DEFAULT) all the tasks "NSLog(#"1111");"
and "
while (1) {
sleep(0.5);
"
will be added to the same target queue. As the result I can assume that in the first case block with WHILE will be executed first, and because it will not finish never, the next task in the queue(NSLog(...)) will be never called.
You can try to use different priorities for the queues (DISPATCH_QUEUE_PRIORITY_LOW f.e.).
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.