How do I prepare my UI in a background thread? - ios

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.

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.

How to build UIActivityIndicatorView

When using a UIActivityIndicatorView, it is possible to add this view to your view hierarchy and start animating it.
After that you are completely save to block the main thread (not that this is a good approach), there is basically nothing that I know of, that could stop the activity indicator from spinning.
My question is:
How is this done? It seems like UIActivityIndicatorView uses its own thread for rendering.
Is this something that can be achieved with my own views?
I have a CoreAnimation animation that I want to keep playing while the main thread might be blocking for a couple of milliseconds.
How to do that? Thanks for any help or ideas!
//EDIT: To clarify my question: I want to know what Apple does to get UIActivityIndicatorView animating even when you block the main thread. When I trigger my own CoreAnimation and I block the main thread, the animation itself stops. Furthermore to the question what Apple does to achieve that under the hood, I want to know, if I can achieve this myself, with public API.
You best solution is to use a background thread for long processing while keeping the main thread only for display purpose. That way, you will be able to display your view without blocking and run your long precessing at the same time.
You can use Grand Central Dispatch (GCD) dispatch_async to run your long processing code on another thread and then call dispatch_async on the main thread to refresh your UI.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
// Your long processing code
dispatch_async(dispatch_get_main_queue(),
^{
// Refresh UI here
});
});

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.

DrawRect not called due to active main thread

I have an architecture that takes input from the mic and then performs some calculations and then should render to screen.
The issue is that calling setNeedsDisplay never triggers a call to drawRect because the main thread is running the calculations.
What would be the best way to thread this?
Create a single serial queue and dispatch the work to this background queue using GCD and dispatch the final setNeedsDisplay back to the main queue, or is there a more efficient way of doing this?
keep everything long running off the main thread. that is best in my opinion. Long running calculations are also something
try to never block the UIThread
...work to this background queue using GCD and dispatch the final
setNeedsDisplay back to the main queue, or is there a more efficient
way of doing this?
Based on your pretty vague description, I'd say what you suggested is the best approach.
And if you do this with GCD, your code will be easy to read since the blocks of work you perform are inline in your code making it easy to understand what is going on.
Create a single serial queue and dispatch the work to this background queue using GCD and dispatch the final setNeedsDisplay back to the main queue, or is there a more efficient way of doing this?
You should use the highest level API available to you. In this case, it's NSOperation or one of its subclasses. Probably, NSBlockOperation is the one you want. You should
create a block operation with the block you want executing
Set its completion handler to invoke setNeedsDisplay
Stick it on an NSOperationQueue.
The completion handler needs to invoke setNeedsDisplay on the main thread. You can do this by sending performSelectorOnMainThread:withObject:waitUntilDone: to the view e.g.
[myViewThatNeedsUpdating performSelectorOnMainThread: #selector(setNeedsDisplay)
withObject: nil
waitUntilDone: NO];
I think this is a better approach than using GCD directly because it is more in the Objective-C idiom, it separates the work you are doing from the notification at the end and gives you many more options for how things get done than raw GCD. For instance, if you want several of these things to happen sequentially, you can make some operations dependencies of others without having to write lots of code.

How to create a timer in background thread in iOS

I need to create two timers. One is on the UI thread, the other one is on the background thread. These timers are independent from each other.
Scenario that I will be using; I basically need this to test the responsiveness of UI thread. TImer in uI thread updates lastUpdatedDatetime property every 200ms in UI thread. There is also a background thread that polls this lastupdatedDatetime property every 200ms.
Does anyone know how can I achieve this?
The point of NSTimer is to be able to schedule things to be run on a thread (usually the main thread) while it is handling other events on a run loop. If all you want to do on the background thread is to poll something every 200 ms, then it is far easier to not use an NSTimer and to instead just sleep the background thread. So setup an NSTimer as usual on your main thread and on the background thread do something like:
while (stillRunning) {
usleep(200*1000);
// Do something with lastUpdatedDatetime
}
This technique is wasteful of a thread but is probably more deterministic for testing purposes than using Grand Central Dispatch.
Keep in mind if lastUpdatedDatetime is an NSDate that it should be set as an atomic property so that when you access it on the background thread you are sure to receive a valid object.
look into dispatch_async and dispatch_after
dispatch_async will let you fire off a call to another thread, this is what I use to do main thread changes.
dispatch_after will let you delay a dispatch_async for a number of seconds.
These two in conjunction will let you go back and forth between threads.
here is the documents on Grand Central Dispatch

Resources