如何改善 UITableview 中的加载图像?

Posted

技术标签:

【中文标题】如何改善 UITableview 中的加载图像?【英文标题】:How to improve load image in UITableview? 【发布时间】:2016-10-01 02:52:21 【问题描述】:

我在表格视图中加载 imageview 时遇到问题。加载太慢了。我在表格视图中使用了很多部分。有我的代码:

   - (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;

请帮助我通过 UItableview 中的很多部分改进更快的加载图像。感谢您的任何解决方案!

【问题讨论】:

【参考方案1】:

有一点会有所帮助,那就是与分段表模型相匹配的数据结构,它是一个数组数组。你快到了,因为你有所有的子阵列。像这样构建一个(当所有子数组都构建时,而不是在 cellForRow 中):

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

这将使您将大条件扁平化为一行:

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

你可以在其他地方使用它,比如numberRowsInSection

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

稍微棘手的问题是让这些图像异步加载并被缓存。 here 和许多 others 讨论了完全原生的方法。

将这个想法应用到您的代码中,这是一个返回缓存图像或获取、缓存并返回的方法...

// 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];
    

现在您的简化 cellForRowAtIndexPath 可以如下所示:

- (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;

这里的想法是你要么有一个缓存的图像,在这种情况下,只需将单元格的 imageView 图像设置为那个,或者你必须获取一个。在获取的情况下,不确定该行是否在获取期间被滚动。重新加载当前行以使其使用(现在缓存的)图像进行更新。

【讨论】:

【参考方案2】:

有图像缓存的概念,图像视图在后台异步加载图像。参考以下链接 https://github.com/nicklockwood/AsyncImageView

【讨论】:

缓存和异步加载是不同的想法。有很多专门用于 UIImageView 的网络代码来完成它自己的加载,这是一个好主意(也很容易在没有网络代码的情况下构建)。这些图像视图实例自然会缓存图像,但在滚动期间重复使用单元格的表格视图中并没有多大好处。【参考方案3】:

使用以下很棒的库在后台下载图片。

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);
     
];

【讨论】:

将图像加载工作移动到图像视图是个好主意,但是对于包含在 uitableview 单元格中的图像视图来说,这还不够。视图的缓存级别太低,因为视图被重用。 您可以检查重用单元的解决方案:***.com/questions/23741124/…

以上是关于如何改善 UITableview 中的加载图像?的主要内容,如果未能解决你的问题,请参考以下文章

在 UITableView 重新加载时从 SDWebImage 设置图像

uitableview 中的异步图像加载

在加载 UITableVIew 之前从解析中检索图像?

如何将图像从 plist 加载到 UITableView?

在 UITableView 内的 UIImageView 中从 Web 加载图像

使用大型数据库时,如何避免 UITableView 中的自定义单元格加载时间过长