Reputation: 497
I have some code which im running like
//codeline1 //codeline2
//codeline3 (UIMAGE)
//coldline4 //codeline5
How do i make codeline 3 run as a separate thread? so if the image takes a while to load, the rest of the code still loads.
A lot of the examples uses methods to launch new threads but i want it to run just that one line in a new thread without it being in another method.
[self performSelectorOnMainThread:@selector(myMethod) withObject:nil waitUntilDone:NO];
[self performSelectorInBackground:@selector(myMethod) withObject:nil];
Upvotes: 2
Views: 315
Reputation: 47114
The pain with image loading is that is is (always?) delayed until the image is actually displayed. It is displayed by the UI thread. So even if you create the UIImage
object in a separate thread, this will be done in the blink of an eye, because nothing really happens (i.e. data is not decompressed), and the delay induced by decoding will delay the UI thread as it will try to display the image.
I never really found a good way around this, apart from trying to read one pixel from the image in the background thread, forcing it to read in the entire image (in the background thread). If you then display the image in the UI thread, the image displays a lot quicker, since the UI thread is not burdened with the decoding step. But note that the CPU will have to decode the thing one way or the other, so the UI interaction still gets a little choppy when decoding happens in the background.
edit I have to clarify/correct myself here: the decoding doesn't block the main thread, but it is delayed by it. The image will only be decoded as soon as the UI thread thinks it's time to do so. This may interfere with the user experience you would like to provide. To circumvent this, and make sure that the image is pre-loaded, you could try to read 1 pixel in the background. An alternative solition may be to use CATiledLayer instead of the UIImage approach, but that's not quite a drop-in replacement.
Upvotes: 2
Reputation: 45148
You can use GCD
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0);
dispatch_async(backgroundQueue, ^{codeline3;}); //unlike performSelectorInBackground:... you can write anything inside the block, not only a single method
and if you need to update some UI or other things that has to be done in the main thread you can call:
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue,^{[self doSomethingInThenMainThread];});
from anywhere, (even inside of codeline3 if it were a method) and you are done ;)
This is the most efficient and recommended way by Apple. (WWDC2010 - Session 131 - Performance Optimization in iPhone OS) The only con is that it won't work in iOS 2.x or 3.x, you need at least 4.0.
Standford iPhone Course has simple and short examples about GCD and multithreading, when to change to background threads and when to go back to the main thread. Take a look at them for further info.
Hope it helps
Upvotes: 0