0

I have a problem when i load imageview in table view. It's Loading so slowly. I use a lot of section in my table view. There is my code:

   - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 TrangChuTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellTrangchu" forIndexPath:indexPath];

theGame *thegameObj;
if([indexPath section] == 0){

    thegameObj = [theZingArray objectAtIndex:indexPath.row];

}else if([indexPath section] == 1){

    thegameObj = [theBitArray objectAtIndex:indexPath.row];

}else if([indexPath section] == 2){

    thegameObj = [theMobayArray objectAtIndex:indexPath.row];

}else if([indexPath section] == 3){

    thegameObj = [theGateArray objectAtIndex:indexPath.row];

}else if([indexPath section] == 4){

    thegameObj = [theVcoinArray objectAtIndex:indexPath.row];

}else if([indexPath section] == 5){

    thegameObj = [theGarenaArray objectAtIndex:indexPath.row];

}else if([indexPath section] == 6){

    thegameObj = [theOncashArray objectAtIndex:indexPath.row];

}else if([indexPath section] == 7){

    thegameObj = [theMobiphoneArray objectAtIndex:indexPath.row];

}else if([indexPath section] == 8){

    thegameObj = [theVinaphoneArray objectAtIndex:indexPath.row];

}else if([indexPath section] == 9){

    thegameObj = [theViettelArray objectAtIndex:indexPath.row];

}
NSURL *urlImage = [NSURL URLWithString:thegameObj.image];
NSData *imageData = [NSData dataWithContentsOfURL:urlImage];
cell.txtQuantity.text=@"1";
UIImage *image= [UIImage imageWithData:imageData];
cell.imageView.layer.cornerRadius=5;
cell.imageView.layer.masksToBounds=YES;
cell.imageView.image = image;
cell.labelName.text = thegameObj.objectName;

if([[AppDelegate appDelegate]checkIP])
{
    [cell.txtQuantity setBackgroundColor:[UIColor whiteColor]];
    [cell.txtQuantity.layer setBorderColor:[UIColor grayColor].CGColor];
    [cell.txtQuantity.layer setBorderWidth:1.0];
    [cell.txtQuantity.layer setCornerRadius:5];
    cell.labelPrice.text = [NSString stringWithFormat:@"%@ (%@)", [NSNumberFormatter localizedStringFromNumber:thegameObj.price numberStyle:NSNumberFormatterDecimalStyle], loadCurrency];

}
else
{
    [cell.lbdetail setTitle:@"detail" forState:UIControlStateNormal];
    cell.txtQuantity.hidden=YES;
    cell.labelPrice.hidden=YES;
    cell.lbgia.hidden=YES;
    cell.lbsl.hidden=YES;
    cell.lbdetail.hidden=YES;

}

cell.objArray = thegameObj;
cell.currency = loadCurrency;
/*
 [cell.addToCartButton addTarget:self action:@selector(addToCart:) forControlEvents:UIControlEventTouchUpInside];
 cell.addToCartButton.tag = [NSString stringWithFormat:@"%d_%d", (NSInteger)[indexPath section], (NSInteger)[indexPath row]];
 */
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;


return cell;
}

Please help me improve more faster load image with alot of section in UItableview. Thank you for any solution!

Hoang Aloevera
  • 131
  • 2
  • 10

3 Answers3

2

There is concept of image caching with which image view loads images asynchronously in background. Refer following link https://github.com/nicklockwood/AsyncImageView

vje1998
  • 691
  • 6
  • 19
  • 1
    Caching and loading async are distinct ideas. There's a lot of net code specializing a UIImageView to do it's own loading, and that's a good idea (also pretty easily build-able without net code). These image view instances naturally cache the image but that doesn't do much good in a table view who's cells are reused during scrolling. – danh Oct 01 '16 at 03:15
2

One thing that will help is a data structure that matches a sectioned table model, which is an array of arrays. You're almost there, since you have all of the sub-arrays. Build one like this (when all the sub-arrays are built, not in cellForRow):

NSArray *model = @[ theZingArray, theBitArray, /*... and so on */];

That will let you flatten the big conditional to one line:

thegameObj = model[indexPath.section][indexPath.row];

You can use that elsewhere, like in numberRowsInSection

NSArray *sectionArray = model[indexPath.section];
return sectionArray.count;

The slightly tougher problem is to have those images load async and get cached. A fully native approach is discussed here and many others.

Applying this idea to your code, here's a method that returns either a cached image, or fetches, caches and returns...

// declare this and BE SURE TO INITIALIZE IT
@property(strong,nonatomic) NSMutableDictionary *imageCache;

// return an image found at the url string, if one is cached return it, otherwise,
// fetch it, cache it and return it
- (void)imageAtURLString:(NSString *)urlString completion:(void(^)(UIImage *, BOOL))completion {
    if (self.imageCache[urlString]) {  // if it's cached
        completion(self.imageCache[urlString], YES);
    } else {  // fetch and cahce
        NSURL *url = [NSURL URLWithString:urlString];

        NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            if (data) {
                UIImage *image = [UIImage imageWithData:data];
                if (image) {
                    self.imageCache[urlString] = image;
                    dispatch_async(dispatch_get_main_queue(), ^{
                        completion(image, NO);
                    });
                }
            }
        }];
        [task resume];
    }
}

Now your simplified cellForRowAtIndexPath can look like this:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellid"];  // fixme

    theGame *thegameObj = model[indexPath.section][indexPath.row];
    NSString *urlString = thegameObj.image;
    UIImageView *imageView = cell.imageView;

    [self imageAtURLString:urlString completion:^(UIImage *image, BOOL wasCached) {
        if (wasCached) imageView.image = image;
        else [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    }];

    return cell;
}

The idea here is that you either have a cached image, in which case, just set the cell's imageView image to that, or you had to fetch one. In the case of the fetch, it's uncertain whether the row got scrolled away during the fetch. Reload the current row to cause it to update with the (now cached) image.

Community
  • 1
  • 1
danh
  • 62,181
  • 10
  • 95
  • 136
0

Use following awesome library for download image in background.

https://github.com/rs/SDWebImage

UIImageView * thumbnail = [[UIImageView alloc] init];
NSURL *urlToPicture1 = [NSURL URLWithString:currentMarker.thumbnail];

[thumbnail sd_setImageWithURL:urlToPicture1 placeholderImage:[UIImage imageNamed:@"placeholder.png"] options:SDWebImageProgressiveDownload completed:^(UIImage * image, NSError * error,SDImageCacheType cachedType, NSURL * imageURL){
    if(image){
        [thumbnail setImage:image];
        NSLog(@"Complete = %d, error = %@",cachedType, error);
    } 
}];
Sandy Patel
  • 768
  • 7
  • 19
KKRocks
  • 8,222
  • 1
  • 18
  • 84
  • Its nice idea to move the image loading work to the image view, but it's insufficient for a an image view contained in a uitableview cell. Caching at the view is too low level because the view is reused. – danh Oct 01 '16 at 03:45
  • you can check solution for reuse cell : http://stackoverflow.com/questions/23741124/sdwebimage-uitableviewcell-wrong-image-when-scrolling – KKRocks Oct 04 '16 at 13:19