Problem with asynchronous loading of ScrollView content
I have a UIScrollView with a lot of UIImageView inside. In the loadView method, I assign a temporary image to each image subview of the UIImageView and start multiple threads to download images from the internet asynchronously. Each thread loads and assigns images as follows:
NSData *data = [NSData dataWithContentsOfURL:URL];
UIImage *img = [UIImage imageWithData:data];
img_view.image = img;
Here's the problem: I expect the image to be resized after every image loaded. I can only see temporary images until all images are loaded. The UIScrollView still interacts while the images are loading - I can scroll the temporary images inside it and see the scrollers and nothing is blocking the loop, but the loaded images are not refreshed ..
What I was trying to do:
- Calling sleep () on the download thread doesn't help.
- Call setNeedsDisplay for each ImageView inside ScrollView and for ScrollView - doesn't help.
What happened? Thanks.
Update. I tried some experiments with the number of threads and the number of images uploaded. Now I'm sure - images are redrawn only when the stream is finished. For example if I download 100 images with one streaming image update once after all images are loaded. If I increase the number of threads to 10 - update the image 10 times - there are 10 images for each update.
Another update. I fixed the issue by watching a new stream from the streams being loaded every time one image was loaded and exiting the current stream (instead of loading multiple images into one stream in a loop and only exiting the stream when everything had been downloaded). Obviously this is not a good decision and there must be a correct approach.
a source to share
I would give up using streams for this use and use the asynchronous API to find data on the web.
NSData *data = [NSData dataWithContentsOfURL:URL];
This function call sends some data from the socket and then sits there and blocks the thread until a response is received. If you don't make synchronous calls, you don't have to worry about blocking the UI thread, and your problem becomes much easier.
I would use the ASIHTTP Library or NSURLConnection to access your data and do all your updates in one thread. There is a small learning curve in the API, but it is substantially less than proper thread handling. I would highly recommend the ASIHTTP library, it's just rocks. You can set a request delegate to the progress widget and activate the connection to use the edge.
a source to share
Hi Newbee (no phun required)
The situation you are describing sounds like a candidate for NSOperation
and NSOperationQueue
you can simply "download" all of these methods and let them know how best to get the image. If you keep creating new threads, then at some point you lose the benefits of threading, i.e. the overhead grows for each thread and there is only so much CPU time.
Start by sorting the list of image URLs so that those farthest from the user (in the scrollView sense) are loaded last, then start adding the load operation to the NSOperationQueue and then start the operation. These classes will then balance things out and save you the hassle of coding logic to deal with scenarios that might erupt.
I found this helpful a few weeks ago: NSOperation Tutorial
Markus Zarra provides a good simple example to get you started.
EDIT: Oops ... and answer your question :) if that doesn't update your images, you may need to send a specific "update" message when the operation is done. If this is a big part of your application, then I would recommend that you create a PictureObject and move the functionality inside that application. So when you add a PictureObject, you instantiate with a url and display a dummy picture as you view it. You pass this PictureObject to your NSOperation, which gets the url, downloads the image, and sets it to the PictureObject. This way it is completely asynchronous and you don't have to deal with loops or testing if the image is loaded etc. Etc. Hope this makes sense.
a source to share