如何让UITableViewCell图像更新到下载的图像,而不必滚动UITableView

我试图拉我平常的UITableView +asynchronous下载+caching技术自己的味道。 我正在做的是,对于cellForRowAtIndexPath中出现的每个单元格:

1-Check if it's corresponding thumbnail image is already 'cached' in /Library/Caches 2-If it is, just use that. 3-If not, load a default image and enqueue an NSInvocationOperation to take care of it: 4a-The NSInvocationOperation gets the image from a remote server 4b-Does the UIGraphicsBeginContext thing to scale down the image to 40x40 4c-saves the scaled down version to /Library/Cache 4d-'SHOULD' update the cell's image to the new downloaded and downsized image, if the cell is still visible. 

但是,我不知道如何让细胞更新他们的图像,除非我手动滚动他们closures和回到屏幕上。 唯一能够解决的问题是在完成之后,NSOperation通过performSelectorOnMainThread调用主线程,然后主线程可以调用[viewtable reloadData]。 但是这看起来很浪费:每当一个单元格的新图像准备就绪时,我正在重新加载整个表格。

作为一个less浪费的方法,我有主线程而不是设置一个布尔标志,然后,当scrollViewDidEndDecelerating,如果该标志设置,调用[viewtable reloadData]。 使用这种方法,只有当用户完成滚动时才刷新单元格。

但是,我仍然希望只更新可见的单元格,如果它们的caching图像已经准备好,但仍然可见(意味着用户不会从视图中滚动它们)。

这是我的代码到目前为止:

  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: CellIdentifier] autorelease]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; cell.selectionStyle = UITableViewCellSelectionStyleGray; } // Configure the cell... cell.textLabel.text = [[dbData objectAtIndex:indexPath.row] objectAtIndex:0]; cell.detailTextLabel.text = [[dbData objectAtIndex:indexPath.row] objectAtIndex:1]; NSString *ImageName = [[dbData objectAtIndex:indexPath.row] objectAtIndex:2]; NSString *cachedImageName = [[[ImageName stringByDeletingPathExtension] stringByAppendingString:thumbnailSizeSuffix] stringByAppendingPathExtension:@"png"]; NSString *cachedImagePath = [cachePath stringByAppendingPathComponent:cachedImageName]; if([[NSFileManager defaultManager] fileExistsAtPath:cachedImagePath]) cell.imageView.image = [UIImage imageWithContentsOfFile:cachedImagePath]; else { cell.imageView.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:defaultNeedsDownloadIconFile ofType:@"png"]]; NSArray *package = [NSArray arrayWithObjects:ImageName, cachedImagePath ,referencingTable, nil]; NSInvocationOperation *concurrentImageLoader = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadURI:) object:package]; [concurrentQueue addOperation: concurrentImageLoader]; [concurrentImageLoader release]; } return cell; } 

对于NSInvocationOperation的“内核”,我试过这个:

 - (void)loadURI:(id)package { NSArray *payload = (NSArray*)package; NSString *imageName = [payload objectAtIndex:0]; NSString *cachedImagePath = [payload objectAtIndex:1]; NSString *imageURL = [NSString stringWithFormat:@"http://www.useanddisposeof.com/VentanaSurDB/%@/photo/%@",[payload objectAtIndex:2], imageName]; UIImage *newThumbnail = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]]; if(!newThumbnail) newThumbnail = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:defaultNotFoundIconFile ofType:@"png"]]; UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, thumbnailSize.width, thumbnailSize.height)]; imageView.layer.borderColor = [UIColor blackColor].CGColor; imageView.layer.cornerRadius = 4.0; imageView.layer.masksToBounds = YES; imageView.layer.borderWidth = 1.0; imageView.image = newThumbnail; UIGraphicsBeginImageContext(CGSizeMake(thumbnailSize.width, thumbnailSize.height)); [imageView.layer renderInContext:UIGraphicsGetCurrentContext()]; newThumbnail = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); [imageView release]; [UIImagePNGRepresentation(newThumbnail) writeToFile:cachedImagePath atomically:YES]; [self performSelectorOnMainThread:@selector(updateCellImage) withObject:nil waitUntilDone:NO]; } 

这是刷新tableview的主线程中的代码:

 - (void)updateCellImage:(id)package { needReloadCachedImages = YES; } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { // I know, I know, there's a race condition here.. I'll fix it if this code stays. if(needReloadCachedImages) [self.tableView reloadData]; needReloadCachedImages = NO; } 

有任何想法吗?

但是这看起来很浪费:每当一个单元格的新图像准备就绪时,我正在重新加载整个表格。

reloadData只重载可见单元格,而不是整个表格,这就是你所说的。

如何给一些开源的尝试 ? 对于一个更简单的问题来说,这太费劲了。 还有一个很好的教程 ,这可能会给你一个你可能做错了什么的想法。