Going from main thread to background - ios

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.
});

Related

Are uikit methods guaranteed to be run on main thread?

Anything UI related work needs to be run on main thread for iOS. Sometimes we need to do some async job like downloading a image and we probably would use dispatch_async and when the download finishes we get the main thread and display it like something like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
UIImage *overlayImage = [self faceOverlayImageFromImage:_image];
dispatch_async(dispatch_get_main_queue(), ^{
[self fadeInNewImage:overlayImage];
});
});}
But when we load an image locally we usually just do this without dispatching on main thread:
UIImageView *imageView = [[UIImageView alloc] initWithImage:#"myimage.png"];
My question is are they guaranteed to be run on main thread? If yes why should we dispatch it using dispatch_get_main_queue()? If no why don't we need to dispatch every ui related work on main thread?
You're confused.
A given call chain is either run on the main thread or on a background thread. Most of the code you deal with is invoked through system events, and is guaranteed to be run on the main thread. There are only a limited number of cases where your code will be invoked from a background thread. Only in those cases do you need to wrap UIKit calls in code that redirects the call to the main thread.
The most common reason for your code to be running from a background thread is because you invoked it that way - often using Grand Central Dispatch.
You might invoke some code like this:
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
//This code will be on a background thread
//Do time-consuming work here
//This calls back to the main thread.
DispatchQueue.main.async { [weak self] in
//Put your code to display your results in the UI here.
}
}
View controller functions, button actions, etc are always called on the main thread. If the system calls some method on a background thread, it will be well documented.
Some functions that take completion handlers invoke those completion handlers on a background thread. The NSURLSession (URLSession) class, for example, invokes its completion handlers and delegate methods on a delegate queue that defaults to a background thread. So when you pass a completion handler to an instance of URLSession, you need to make sure your UIKit code is wrapped in a call to dispatch_async() (DispatchQueue.main.async() in Swift 3) or a similar method of passing code to the main thread to execute.
Most UI related actions need to be performed on the main thread for them to work properly. But simply using a UI... class does nothing itself to ensure it is run on the main thread.
That's your job as the programmer. If you do something (like download data or perform a long running task) in the background and then need to update the UI, you must ensure the UI code is done on the main thread.
Keep in mind that creating UIImage instances can safely be created on a background thread. That's safe.
tl;dr - no, nothing is guaranteed to be run on the main thread. And you do need to dispatch every UI related work on the main thread unless you are already on the main thread.

While dispatch_sync(kBgQueue, ^{}); using at background the foreground UI getting freeze at a moment

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

setNeedsDisplay doesn't work on background thread

I am calling the setNeedsDisplay method in a new thread, but I don't see any changes in my view. What should I do to see all my changes after calling setNeedsDisplay in a new thread?
You can't update the user interface on a background thread. In your background thread, change
[object setNeedsDisplay];
to
[object performSelectorOnMainThread:#selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
Any updates involving the UI must be made on the main thread. Generally, background threads are used for time-intensive tasks, such as downloading files, parsing data, etc...
Your main thread is responsible for updating the User Interface and responding to the users events and actions. That's the main reason we have background threads, to manage memory usage and to increase performance, by keeping the main thread as free as possible to respond to the user, while time-intensive tasks, which would normally block the main thread, happen in the background.
After you have processed all necessary data and information on your background thread, you must commit any changes to the UI according to your data by dispatching it to the main thread:
dispatch_async(dispatch_get_main_queue(), ^{
//do UI stuff
});
Another way of dispatching to the main thread is as follows:
[self performSelectorOnMainThread:#selector(doUIStuff:) withObject:stuff waitUntilDone:NO];

dispatch_sync inside a dispatch_async

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.

UIWebView stringByEvaluatingJavaScriptFromString hangs on iOS5.0/5.1 when called using GCD

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!')"];
});

Resources