开发者

How to download a lot of images asynchronously and place them in a tableView cell's imageView

开发者 https://www.devze.com 2023-02-08 06:14 出处:网络
I would like to know how I could asynchronously download a lot of images (link开发者_StackOverflow parsed via xml) and place them in a tableView\'s cell. I tried MarkJ\'s tutorial, and it worked perfe

I would like to know how I could asynchronously download a lot of images (link开发者_StackOverflow parsed via xml) and place them in a tableView's cell. I tried MarkJ's tutorial, and it worked perfectly, apart from the fact that I want them to display in the cell's imageView. If you can tell me how to do this that would be great.


I have a similar case, but my data format is JSON rather than xml. The downloading and asynchronous part should be very similar. I decided to try it with Objective-C blocks and GCD's dispatch_async method. The important parts of my code are below, with some un-needed details left out.

I have an NSDictionary that I use to cache the images, called images. The first step is to check to see if I have an image for the current NSIndexPath. If so, I simply return that image. If not, I create a placeholder image, start the download of the real image, and return the placeholder.

The "start the download of the real image" part, consists of checking to see if the queue I want to use already exists, and if not creating it. I then make an asynchronous call on a background thread to NSData's convenience method dataWithContentsOfURL. This is a blocking call, but it's on a background thread, so the UI stays responsive. When the call returns I create a UIImage out of the data, cache the image, and retrieve the cell for the indexPath. I then make another dispatch_async call that simply sets the imageView.image property on the cell. The key here is using dispatch_get_main_queue() to get a reference to the queue that manages the main thread, because only the main thread has permission to update the UI.

RootViewController.h

#import <UIKit/UIKit.h>

@interface RootViewController : UITableViewController {

    //An array of dictionary objects
    NSArray *tweets;

    //A place to cache images
    NSDictionary *images;

    // the dispatch queue to load images
    dispatch_queue_t queue;
}

@property (nonatomic, retain) NSArray *tweets;
@property (nonatomic, retain) NSDictionary *images;

@end

RootViewController.m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = ...;
    //set up the cell
    ....
    cell.imageView.image = [self imageForRowAtIndexPath:indexPath];
    return cell;
}

- (UIImage *)imageForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // get the dictionary for the indexPath
    NSDictionary *tweet = ...;

    // get the user dictionary for the indexPath
    NSDictionary *user = [tweet objectForKey:@"user"];

    // get the user's id and check for a cached image first
    NSString *userID = [user objectForKey:@"id_str"];
    UIImage *image = [self.images objectForKey:userID];
    if(!image)
    {
        // if we didn't find an image, create a placeholder image and 
        // put it in the "cache". Start the download of the actual image
        image = [UIImage imageNamed:@"Placeholder.png"];
        [self.images setValue:image forKey:userID];

        //get the string version of the URL for the image
        NSString *url = [user objectForKey:@"profile_image_url"];

        // create the queue if it doesn't exist
        if (!queue) {
            queue = dispatch_queue_create("image_queue", NULL);
        }

        //dispatch_async to get the image data
        dispatch_async(queue, ^{

            NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
            UIImage *anImage = [UIImage imageWithData:data];
            [self.images setValue:anImage forKey:userID];
            UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];

            //dispatch_async on the main queue to update the UI
            dispatch_async(dispatch_get_main_queue(), ^{
                cell.imageView.image = anImage;
            });
        });
    }

    // return the image, it could be the placeholder, or an image from the cache
    return image;
}


Extend NSOperation (something like ImageDownloadOperation) and add the download operations to a Global NSOperationQueue. Have a callback on the table view cells that sets the image when the download is completed. Sorry there is no code example as it would be a large amount of custom code. This is how I've done it with links parsed out of JSON objects.

0

精彩评论

暂无评论...
验证码 换一张
取 消