如何改善 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 设置图像