Idrees Ashraf
Idrees Ashraf

Reputation: 1383

Asynchronous image loading

I am downloading images in table asynchronously. when table appears first time then connecion:didrecieveData is not called but when I move the up or down then it is called and images are displayed. kindly help

table View class:

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

    static NSString *CellIdentifier = @"Cell";

    customiseForVideos *cell =(customiseForVideos *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:@"customiseForVideos" owner:self options:nil];
        cell=tblCell;
    }
    else{
        AsyncImageView* oldImage = (AsyncImageView*)
        [cell.contentView viewWithTag:999];
        [oldImage removeFromSuperview];

    }
    [cell.imageActivity startAnimating];

    CGRect frame;
    frame.size.width=65; frame.size.height=70;
    frame.origin.x=24; frame.origin.y=12;
    AsyncImageView* asyncImage = [[[AsyncImageView alloc]
                                   initWithFrame:frame] autorelease];
    asyncImage.tag = 999;
    NSURL* url = [NSURL URLWithString:[[videoCollection objectAtIndex:indexPath.row] videoImageUrl]];
        //NSLog(@"%@",url);
    [asyncImage loadImageFromURL:url activity:cell.imageActivity];

    [cell.contentView addSubview:asyncImage];

    if((indexPath.row%2)==0)
        cell.backgroundView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"green-cell-row.png"]] autorelease];
    else{
        cell.backgroundView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"blue-cell-row.png"]] autorelease];
    }
    return cell;
}

AsyncImageView class:

- (void)loadImageFromURL:(NSURL*)url activity:(UIActivityIndicatorView *)cellActivity {
    activityOnCell=cellActivity;
    activityOnCell.hidden=NO;
    if (self.connection!=nil) { [self.connection release]; } //in case we are downloading a 2nd image
    if (data!=nil) { [data release]; }

    NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
    self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; //notice how delegate set to self object
    NSLog(@"%@",request);
        //TODO error handling, what if connection is nil?
}


//the URL connection calls this repeatedly as data arrives
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData {
    if (data==nil) { data = [[NSMutableData alloc] initWithCapacity:2048]; } 
    [data appendData:incrementalData];
}

//the URL connection calls this once all the data has downloaded
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
    //so self data now has the complete image 
    [self.connection release];
    self.connection=nil;
    if ([[self subviews] count]>0) {
        //then this must be another image, the old one is still in subviews
        [[[self subviews] objectAtIndex:0] removeFromSuperview]; //so remove it (releases it also)
    }

    //make an image view for the image
    UIImageView* imageView = [[[UIImageView alloc] initWithImage:[UIImage imageWithData:data]] autorelease];
    //make sizing choices based on your needs, experiment with these. maybe not all the calls below are needed.
    imageView.contentMode = UIViewContentModeScaleAspectFit;
    imageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth || UIViewAutoresizingFlexibleHeight );
    [self addSubview:imageView];
    imageView.frame = self.bounds;
    [imageView setNeedsLayout];
    [self setNeedsLayout];
    activityOnCell.hidden=YES;

    [data release]; //don't need this any more, its in the UIImageView now
    data=nil;
}

Upvotes: 0

Views: 2687

Answers (4)

David Ben Ari
David Ben Ari

Reputation: 2309

there is a great 3rd party package that will do everything for you in one line of code: https://github.com/rs/SDWebImage.

all you need to do is import this category (#import "UIImageView+WebCache.h")

and then in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{} you should set the cell's image with one simple method:

    [cell.imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:@"noPic.png"]];

and you are done :)

Upvotes: 0

Farhan Patel
Farhan Patel

Reputation: 506

Loading images into a TableView is a common problem. So much so that there are drop in solutions. You are better off using one of these then trying to design your own. You will save a lot of time, usually find an optimized solution and you can always subclass if you need more features.

reloading the table everytime a new image comes in isn't the best solution. As when you reload if the user is scrolling he loses his position.

use https://github.com/AFNetworking/AFNetworking

Here is how easy it is to do what you need.

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)];

[imageView setImageWithURL:[NSURL URLWithString:@"http://i.imgur.com/r4uwx.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]];

Upvotes: 2

Prabhat Kasera
Prabhat Kasera

Reputation: 1149

Use NSCache to store images temporarily and use url as key and NSData as value.

and in method cellforRowAtIndexPath get value from NSCache object and assign it to imageview. it will stop flickring and will be visible.

Upvotes: 0

Saad
Saad

Reputation: 8947

you are not reloading the tableview after you have received the image. use

[mtableView reloadData]; 

in connection didfinished loading. and if it is not the same class where tableview resides, then make another method and where place the reload table and call this from other class by means of delegate.

Upvotes: 1

Related Questions