views:

182

answers:

2

Hi! I have UIScrollView with lots of UIImageView inside. In the loadView method I assign some temporary image for each of subview UIImageView images and starts several threads to async download images from internet. Each thread downloads and assign images as follows:

    NSData  *data   = [NSData dataWithContentsOfURL:URL];
    UIImage *img    = [UIImage imageWithData:data];
    img_view.image  = img;

Here is the problem - I expects picture will changed after each image downloaded by I can see only temporary images until all images will downloads. UIScrollView still interact while images downloads - I can scroll temporary images inside it and see scrollers and nothing blocks run loop, but downloaded images doesn't updates..

What I tried to do:

  1. Call sleep() in the download thread -- not helps.
  2. Call setNeedsDisplay for each ImageView inside ScrollView and for ScrollView -- not helps.

What's wrong ? Thanks.

Update. I tried some experiments with number of threads and number of images to download. Now I'm sure -- images redraws only when thread finished. For example - if I load 100 images with one thread -- picture updates one time after all images downloads. If I increase number of threads to 10 -- picture updates 10 times -- 10 images appears per update.

One more update. I fixed problem by staring new thread from the downloading threads each time one image downloaded and exit current thread (instead of download several images in one thread in the cycle and exit thread only when all downloaded). Obviously it's not a good solution and there must be right approach.

A: 

Hi Newbee (no phun intended)

The situation you describe sounds like a candidate for NSOperation and NSOperationQueue You can simply "load" everything off to these methods and have them figure out how best to retrieve the picture. If you keep building new threads, then at some point you loose the advantages of threading, i.e. the overhead grows for each thread and there is only so much CPU time to go around.

Start out by sorting the list of URL's for the pictures so that the ones furthest away from the user (in a scrollView sense) get's loaded last, then start adding the load operation off to an NSOperationQueue and then start the Operation. These classes will then balance things out and save you a ton of coding the logic to deal with scenarios that could erupt.

I found this helpful some weeks ago: NSOperation tutorial

Marcus Zarra lays out a nice simple example to get you started.

EDIT: Whoops... and to answer your question:) if this does not result in your pictures updating, then you might need to send a specific "update" message when the operation is done. If this is a large part of your app I would recommend you build a PictureObject and move the functionality inside that. So when adding a PictureObject you instantiate it with a URL and it displays a dummy picture as it's view. The you hand this PictureObject over to your NSOperation who retrieves it's URL loads the picture and sets it on the PictureObject. This way it is async all the way and you don't have to deal with loops or testing if picture is downloaded etc. etc. Hope it makes sense.

RickiG
A: 

I would discourage use of threads for this usage, and use an Asynchronous API for data retrieval on the network.

NSData  *data   = [NSData dataWithContentsOfURL:URL];

This function call sends some data out a socket then sits there and locks the thread until it receives a response. If you don't make any synchronous calls you don't have to worry as much about locking the UI Thread and your problem becomes much simpler.

I would use the ASIHTTP Library or NSURLConnection to access your data, and do all of your updating on one thread. There is a slightly learning curve with the API's but it's substantially smaller than managing threads correctly. I would strongly recommend the ASIHTTP Library, it just rocks. You can set the request delegate to a progress widget and throttle your connection for edge usage.

Brian King