I have the following code in viewDidLoad, which works properly on iOS 4.3, but it hangs on iOS 5/5.1. On iOS 5/5.1, the alert dialog is shown but can not be dismissed, the UI thread freezes, the OK button just can not be clicked.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_sync(dispatch_get_main_queue(), ^{
[self.webview stringByEvaluatingJavaScriptFromString:#"alert('HELLO WORLD!')"];
});
});
Is this a bug?
After test, I consider it as a Bug, and changing code to use
[webView performSelectorOnMainThread:#selector(stringByEvaluatingJavaScriptFromString:) withObject:js waitUntilDone:NO]
will solve it.
Try it in - (void)viewDidAppear:(BOOL)animated instead
Why are you using GCD at all here?
Remember that in GCD there is no guarantee which thread your code will called on, regardless of queue. My guess is that your DISPATCH_QUEUE_PRIORITY_DEFAULT code happens to be running on the main thread, which is then triggering a deadlock on your dispatch_sync() call. This could be verified by examining your thread states in the debugger or Instruments.
Which gets back to my original question: what do you get by doing these convolutions instead of just calling the method directly on the main thread? You are going to block either way.
You can also change your dispatch_sync() to dispatch_async() - that should also suppress a deadlock, but should only be done if you have other concurrency needs and don't need a background thread to block.
Try
dispatch_async(dispatch_get_main_queue(), ^{
[self.webview stringByEvaluatingJavaScriptFromString:#"alert('HELLO WORLD!')"];
});
Related
I have used the
dispatch_sync(kBgQueue, ^{
});
to get response from webservice at background. While getting the response at background the UI getting delay, ie) while typing the on uitextview the keyboard getting freeze at moment.
How to fix this issue?
Thanks in advance..
dispatch_sync will wait for the block to be executed (which is going to take time depending upon the operation). This blocks the main thread where the UI is updated.
In order to get a responsive UI you need to replace dispatch_sync with dispatch_async.
right code:
dispatch_async(kBgQueue, ^{ });
dispatch_sync Submits a block object for execution on a dispatch queue and waits until that block completes.So it will block your main thread.
for move, see this
I am calling JavaScript using stringByEvaluatingJavaScriptFromString. I have UISlider and other UI elements working simultaneously. My whole UI freezes when JavaScript call happens. I looked around about this and found out that making
the call asynchronous should solve the problem.
I have tried two approaches:
[webView performSelectorOnMainThread:#selector(stringByEvaluatingJavaScriptFromString:) withObject:func waitUntilDone:NO]
And this:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
[webView performSelectorOnMainThread:#selector(stringByEvaluatingJavaScriptFromString:) withObject:func waitUntilDone:NO];
});
But none of this seems to work. My UI still freezes for fraction of a second which is noticeable. What am I missing?
Try this:-
dispatch_async(dispatch_get_main_queue(), ^{
[webView stringByEvaluatingJavaScriptFromString:func];
});
performSelectorOnMainThread: executes on main thread (The thread of UI).
I think error in your JavaScript, the script executes infinitely.
I have method A that download images and it start it in background. Then it finished, it runs completion block.
I run method A and I in his completion block. I want to know - now I am in main or in background thread?
You can use:
[NSThread isMainThread];
You're probably still in a background thread. As was mentioned you can check if you're in the background using
[NSThread isMainThread]
If you want to switch to the main thread you can use
dispatch_async(dispatch_get_main_queue(), ^{
// do some things here in the main queue
// for example: update UI controls, etc.
});
I just wanted to confirm why this is needed.
I added this code to the KIImagePager (a cocoapod) to load images that are local to the app (the default code loads images from a url).
Here's my working code based off what a coworker suggested:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
dispatch_sync(dispatch_get_main_queue(), ^{
[imageView setImage:[UIImage imageNamed:[aImageUrls objectAtIndex:i]]];;
});
});
I noticed that if I take out the inner dispatch_sync, it works but not in the way I want (some of the images on the image pager scrollview aren't loaded yet when I start scrolling). But they do eventually load.
My question is this, does the sync call on the main queue get the image back to the UI (which is on the main queue)? Because it does work with the second async removed.
The internal dispatch executes its code block on the main thread. This is required because all UI operations must be performed on the main thread. And you're image downloading code (context in which this snippet is executed) may be on a background thread.
The external dispatch executes its block on a background thread. The block its given is the one that executes on the main thread. Thus, the external block can be safely removed.
Hrs an outline of the idiom you're using.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// do blocking work here outside the main thread.
// ...
// call back with result to update UI on main thread
//
// what is dispatch_sync? Sync will cause the calling thread to wait
// until the bloc is executed. It is not usually needed unless the background
// background thread wants to wait for a side effect from the main thread block
dispatch_sync(dispatch_get_main_queue(), ^{
// always update UI on main thread
});
});
You should only work with UI objects on the main thread. If you don't, you will run into a couple of problems. The first, as you saw, is that UI objects will be delayed in updating. The second is that the app could crash if you try to change UI objects simultaneously from multiple threads. You should only work with UI objects on the main thread.
A UIViewController takes about half a second to load its contents and appear on screen. How can I make them all load in the background and appear when they're ready?
There is a LazyTableImages sample on the Apple developer site.
It shows how to perform the heavy lifting in a background thread and update the UI on the main thread.
PerformSelectorInBackground:withObject: is a possible solution, although a more modern method would be to use asynchronous blocks. You can run code on the main thread from within these blocks to update the UI Safely.
The Concurrency Programming Guide is a good place to find more information and examples of this.
A Background Thread cant update the UI,you can perform all the processing logic in background thread and call the main thread for UI update
Example to load a tableView with Data ,use the background thread to process everything and load the Data, call [tableView reloadData] using the main thread, see Grand central Dispatching to know how to Work with Threads in IOS..
Hope it Helps
Create a GCD queue to process your work in a background thread (read the docs, because my "create" label and options may not be what you want).
You send it to the queue asynchronously, meaning that the call to dispatch_async will make appropriate arrangements for the block of code you give it to run in another thread and it will then return back to you "immediately."
All the work in the block you give it will be executed on a separate thread. Note, at the end, you do another call, this time with the well know main queue. This arranges for that code to run in the main thread, which is mandatory for any UI work.
Also, you really should read the documentation on GCD and especially blocks, because there are memory and cycle considerations. Good luck.
dispatch_queue_t workQ = dispatch_queue_create("bgWorkQ", 0);
dispatch_async(workQ, ^{
// This code is now running in a background thread.
// Do all your loading here...
// When ready to touch the UI, you must do that in the main thread...
disptach_async(dispatch_get_main_queue(), ^{
// Now, this code is running in the main thread.
// Update your UI...
});
});
dispatch_release(workQ);
The easiest way is to use NSObject's - (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg You just pass it a selector and it will happy in the background and not block your UI. Be aware however that there are rules to background threads.
You shouldn't update your UI from the background thread. And you need to make sure the methods you're calling are thread safe.