可能重复:
表视图与图片,加载速度缓慢和滚动
我有一个UITableView
其下载图像的UITableViewCells
从服务器。 我观察到的tableView滚动很慢。
我想,这可能下载的问题,但我已经意识到,该表仍然缓慢滚动下载完成后,图像图标尺寸小于后。
我搜索谷歌,但找不到任何帮助。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
btnBack.hidden = FALSE;
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.backgroundColor = [UIColor clearColor];
cell.textLabel.font = [UIFont fontWithName:@"Noteworthy" size:17.0];
cell.textLabel.font = [UIFont boldSystemFontOfSize:17.0];
cell.textLabel.textColor = [UIColor blackColor];
cell.textLabel.highlightedTextColor = [UIColor blackColor];
}
cell.textLabel.text = [NSString stringWithFormat:@" %@", [test.arrTitle objectAtIndex:indexPath.row]];
NSString *Path;
Path = [NSString stringWithFormat:@"http://%@",[test.arrImages objectAtIndex:indexPath.row]];
NSLog(@"image-->%@",[test.arrImages objectAtIndex:indexPath.row]);
NSString *strImage = Path;
NSURL *url4Image = [NSURL URLWithString:strImage];
NSData *data = [NSData dataWithContentsOfURL:url4Image];
image =[[UIImage alloc] initWithData:data];
cell.imageView.image =image;
[image release];
return cell;
}
虽然我原来的答复,下面,试图解决与异步图像检索相关的几个关键问题,但仍不能从根本上受到限制。 一个适当的实施也将确保,如果你快速滚动,也可见细胞被优先考虑那些原本滚出屏幕细胞。 它还将支持先请求取消(并取消他们为你在适当的时候)。
虽然我们可以添加这些各种各样的功能,下面的代码,它可能是更好的采取一个既定的,成熟的解决方案,利用NSOperationQueue
和NSCache
下面讨论的技术,而且还解决了上述问题。 最简单的解决方案是采用已建立的一个UIImageView
支持异步图像检索类别。 该AFNetworking和SDWebImage库都有UIImageView
类别妥善处理所有这些问题。
您可以使用NSOperationQueue
或GCD做你的懒加载(请参阅并发编程指南针对不同的异步操作技术的讨论)。 前者喜欢,你可以指定精确多少并发操作是允许的,因为许多Web服务器限制多少,他们会从给定的客户接受的并发请求是在加载图片来自网络非常重要的优势。
其基本思路是:
- 提交在一个单独的背景队列中的图像数据的请求;
- 当完成下载图像,调度UI更新回主队列,因为你永远不应该做的背景UI更新;
- 当运行主队列调度最终UI更新代码,确保
UITableViewCell
仍清晰可见,它尚未队并重复使用,因为在该小区中滚动到屏幕。 如果你不这样做,错误的图像可能会暂时出现。
你想的东西,如下面的代码来替换你的代码:
首先,定义为您的属性NSOperationQueue
,你会用来下载图像,以及一个NSCache
用于存储这些图片:
@property (nonatomic, strong) NSOperationQueue *imageDownloadingQueue;
@property (nonatomic, strong) NSCache *imageCache;
其次,初始化这个队列和缓存在viewDidLoad
:
- (void)viewDidLoad
{
[super viewDidLoad];
self.imageDownloadingQueue = [[NSOperationQueue alloc] init];
self.imageDownloadingQueue.maxConcurrentOperationCount = 4; // many servers limit how many concurrent requests they'll accept from a device, so make sure to set this accordingly
self.imageCache = [[NSCache alloc] init];
// the rest of your viewDidLoad
}
三,你cellForRowAtIndexPath
可能是这样的:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
btnBack.hidden = FALSE;
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.backgroundColor = [UIColor clearColor];
cell.textLabel.font = [UIFont fontWithName:@"Noteworthy" size:17.0];
cell.textLabel.font = [UIFont boldSystemFontOfSize:17.0];
cell.textLabel.textColor = [UIColor blackColor];
cell.textLabel.highlightedTextColor = [UIColor blackColor];
}
cell.textLabel.text = [NSString stringWithFormat:@" %@", [test.arrTitle objectAtIndex:indexPath.row]];
// code change starts here ... initialize image and then do image loading in background
NSString *imageUrlString = [NSString stringWithFormat:@"http://%@", [test.arrImages objectAtIndex:indexPath.row]];
UIImage *cachedImage = [self.imageCache objectForKey:imageUrlString];
if (cachedImage) {
cell.imageView.image = cachedImage;
} else {
// you'll want to initialize the image with some blank image as a placeholder
cell.imageView.image = [UIImage imageNamed:@"blankthumbnail.png"];
// now download in the image in the background
[self.imageDownloadingQueue addOperationWithBlock:^{
NSURL *imageUrl = [NSURL URLWithString:imageUrlString];
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
UIImage *image = nil;
if (imageData)
image = [UIImage imageWithData:imageData];
if (image) {
// add the image to your cache
[self.imageCache setObject:image forKey:imageUrlString];
// finally, update the user interface in the main queue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Make sure the cell is still visible
// Note, by using the same `indexPath`, this makes a fundamental
// assumption that you did not insert any rows in the intervening
// time. If this is not a valid assumption, make sure you go back
// to your model to identify the correct `indexPath`/`updateCell`
UITableViewCell *updateCell = [tableView cellForRowAtIndexPath:indexPath];
if (updateCell)
updateCell.imageView.image = image;
}];
}
}];
}
return cell;
}
四,最后,当一个可能倾向于写代码清除在低内存情况缓存,事实证明,它会自动完成,因此这里无需额外处理。 如果您手动模拟仿真内存不足的情况,你不会看到它驱逐了对象,因为NSCache
没有反应UIApplicationDidReceiveMemoryWarningNotification
,但在实际操作过程中,当内存不足时,高速缓存将被清除。 其实, NSCache
不再正常响应低内存情况本身,所以你真的应该为这个通知加入观察者和空在低内存情况缓存。
我可能会建议一堆其他优化(例如,或许还缓存图像到永久存储,以简化未来的经营,我居然把所有的逻辑在我自己的AsyncImage
类),但首先看是否能解决基本的性能问题。
在写这篇文章UITableView
cellForRowAtIndex:
方法
asyncImageView = [[AsyncImageView alloc]initWithFrame:CGRectMake(30,32,100, 100)];
[asyncImageView loadImageFromURL:[NSURL URLWithString:your url]];
[cell addSubview:asyncImageView];
[asyncImageView release];
需要导入AsyncImageView class
和创建对象该类
正如前面所说的:不要做任何繁重的工作中的cellForRowAtIndexPath您可以轻松地通过使用GCD得到解决。 从使用块后台线程加载图像
你应该看看使用一个NSOperationQueue
来处理图像的延迟加载和自定义tableviewcell。 你可以得到样品例如用于NSOperationQueue
这里
谷歌对于这应该设置你在正确的方向特威特定制tableviewcell。
苹果公司在tableViews下载图像的示例项目: LazyTableImages
您存储的图像在一个数组并在填充他们这是可取viewDidLoad
,然后在你cellForRowAtIndexPath:
刚刚成立
cell.imageView.image = [yourImageArray objectAtIndex:indexPath.row];
至于slownesss而言,那是因为你阻塞主线程与下载URLDATA在你cellForRowAtIndexPath
方法,所以在滚动,除非及直至图像不取你的主线程中运行该应用程序将被封锁。
滚动很慢,因为你是在主线程加载图像即同步。 你可以做同样的在后台线程ieasynchronously,看看SDWebImage 。