2

I need to implement the lazy loading concept for the images in my tableview, so that the user will be provided with the textual data initially and later the images.

How can i implement this in to my app.. help needed.. please

Thanks in advance

Shibin

3 Answers3

3

What i have created for a project of mine works as follows; Extend the UITableViewCell class by a category in "UITableViewCell+Async.h" (See some examples if you are not sure what the category thing in Obj C is)

@interface UITableViewCell (Async)

-(void)loadAsyncImage:(NSString*)url withIndex:(NSInteger)index inWidth:(NSInteger)width inHeight:(NSInteger)height;
-(void)loadAsyncBackground:(NSMutableArray*)parameters;

@end

And then in the implementation file "UITableViewCell+Async.m"

#import "UITableViewCell+Async.h"

@implementation UITableViewCell (Async)

-(void)loadAsyncImage:(NSString*)url 
            withIndex:(NSInteger)index 
              inWidth:(NSInteger)width 
             inHeight:(NSInteger)height {

    NSMutableArray* parameters = [NSMutableArray arrayWithCapacity:2];
    [parameters addObject:url];
    [parameters addObject:[NSNumber numberWithInteger:index]];
    [parameters addObject:[NSNumber numberWithInteger:width]];
    [parameters addObject:[NSNumber numberWithInteger:height]];

    self.imageView.tag = index;
    [self performSelectorInBackground:@selector(loadAsyncBackground:) withObject:parameters];

}

-(void)loadAsyncBackground:(NSMutableArray*)parameters {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    NSString* url = [parameters objectAtIndex:0];
    NSInteger index = [[parameters objectAtIndex:1] integerValue];
    NSInteger width = [[parameters objectAtIndex:2] integerValue];
    NSInteger height = [[parameters objectAtIndex:3] integerValue];

    UIImage* image = [Utils getImageResized:url inSize:CGSizeMake(width, height)];

    if (self.tag==index) {
        self.imageView.image = image;
        [self setNeedsLayout];
    }

    [pool release];
}

@end

This basically adds a functionality to the UITableViewCell to load an image in a new background thread, resize the image and set it to the imageview. Checking the tag is added to see if the cell is still waiting for the image, since it can be re-used and another thread for the image could be downloading another image for that re-used cell...

The function in the above code with the signature of;

+(UIImage*)getImageResized:(NSString*)url inSize:(CGSize)size;

checks a local cache of images, downloads the image from the web if not in the cache, saves it to local cache, resizes the image in the given size and returns the image, all done in a sync(blocking) method call. Since this is already the background thread, no harm blocking it for this operation. When the method returns the image, it is set to the cell's imageview if it still has the same tag(not re-used for some other row)

In the cellForRowAtIndexPath method you can add the new category and you should be done;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"......."];
    if (cell == nil) {
................
    }
................
    [cell loadAsyncImage:deal.logo withIndex:indexPath.row inWidth:40 inHeight:40];
................

    return cell;
}
lithium
  • 995
  • 7
  • 13
  • 2
    While we appreciate the effort you put into this post, please don't *just* copy it to every appropriate question. Try to craft each answer to the specific question. Thanks! –  Aug 15 '11 at 15:46
0

Do you mean this

http://developer.apple.com/iphone/library/samplecode/LazyTableImages/Introduction/Intro.html

Liam
  • 7,762
  • 4
  • 26
  • 27
  • Thanks.. I got this one and i added the IconDownloader to my project. But the NSURLConnection:didReceiveData delegate method is not working. so decided to try another way. Can you please help me in solving the delegate issue.? –  May 13 '10 at 16:11
  • @Shibin: that sounds like a new question, use the "Ask Question" button to create a new question rather than asking for help in a comment. – progrmr May 14 '10 at 00:08
  • The question is already posted... http://stackoverflow.com/questions/2824993/nsurlconnectiondelegate-connectiondidreceivedata-not-working –  May 14 '10 at 05:19
  • `NSURLConnection:didReceiveData delegate` method is called if the connection is implemented on the main thread. – Abhishek Bedi Jan 29 '13 at 10:01
0

I used ASINetworkQueue for lazy loading.

In .h file

#import "ASINetworkQueue.h"

and define a variable

//array contains url address of images and a variable of ASINetworkQueue;
NSMutableArray *arrImg;
ASINetworkQueue *queue;

In .m file

static int rowNo = 0;
- (void)downloadImages{

    if(queue == nil){
        queue = [[[ASINetworkQueue alloc] init] autorelease];
    }

    for(NSString* urlString in arrImg)
    {
        NSURL *url = [NSURL URLWithString:urlString];
        ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
        [request setDelegate:self];
        [request setDidFinishSelector:@selector(requestDone:)];
        [request setDidFailSelector:@selector(requestWentWrong:)];
        [queue addOperation:request];
    }

    [queue go];

}


- (void)requestDone:(ASIHTTPRequest*)req{   

    for (int i = 0; i < [arrImg count]; i++) {

        NSMutableString *d = [[NSMutableString alloc] init];
        d = [arrImg objectAtIndex:i];

        //comparing the url to get correct row no of cell
        if([[req.url absoluteString] isEqualToString:d]){
            rowNo = i;
            break;
        }
    }

    //creating a cell with rowNo
    NSIndexPath *index = [NSIndexPath indexPathForRow:rowNo inSection:0];

    UITableViewCell *cell = (UITableViewCell *)[roomTable cellForRowAtIndexPath:index];

    UIImageView *v = (UIImageView *)[cell.contentView viewWithTag:10];

    v.image = [UIImage imageWithData:[req responseData]];

    [cell release];
    cell = nil;
    [v release];
    v = nil;
}

- (void)requestWentWrong:(ASIHTTPRequest*)req{

    for (int i = 0; i < [arrImg count]; i++) {

        NSMutableString *d = [[NSMutableString alloc] init];
        d = [arrImg objectAtIndex:i];

        //comparing the url to get correct row no of cell
        if([[req.url absoluteString] isEqualToString:d]){
            rowNo = i;
            break;
        }
    }
    NSLog(@"No data for cell : %d",rowNo);
    NSLog(@"Request returned an error %@",[req error]);
}
Aleksander Blomskøld
  • 18,374
  • 9
  • 76
  • 82
iPhoneBuddy
  • 49
  • 10