Как получить изображения UITableViewCell для обновления загруженных изображений без необходимости прокрутки UITableView - PullRequest
1 голос
/ 24 октября 2011

Я пытаюсь получить свой собственный вкус обычной UITableView + асинхронная загрузка + техника кэширования.То, что я делаю, для каждой ячейки, которая освобождается от очереди в 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. 

Однако я не могу понять, как заставить ячейки обновлять свои изображения, если я не прокручиваю их вручную и обратнона экране.Единственный хак, который я смог вытащить, - это когда NSOperation вызовет основной поток, когда выполнено, с помощью executeSelectorOnMainThread, и основной поток может затем вызвать [viewtable reloadData].Но это кажется расточительным: я перезагружаю всю таблицу каждый раз, когда готов новый образ ячейки.

В качестве менее расточительного подхода я вместо основного потока устанавливаю флаг bool, а затем, когда scrollViewDidEndDecelerating, если флаг был установлен, выполняется вызов [viewtable reloadData].При таком подходе ячейки обновляются только тогда, когда пользователь выполняет прокрутку.

Но все же, я бы хотел, чтобы обновлялись только видимые ячейки, если их кэшированные изображения готовы, пока они еще видимы (то есть пользователь не прокручивал их за пределами представления).

Вот мой код:

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

И это код обратно в основнойТема для обновления таблицы:

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

Есть идеи?

Ответы [ 2 ]

2 голосов
/ 25 октября 2011

Но это кажется расточительным: я перезагружаю всю таблицу каждый раз, когда новое изображение ячейки готово.

reloadData перезагружает только видимые ячейки, а не всю таблицу, котораяэто то, что вы говорите, что хотите.

1 голос
/ 25 октября 2011

Как насчет того, чтобы дать с открытым исходным кодом попробовать ? Это слишком много усилий для более простой задачи. Есть также хороший учебник , который может дать вам представление о том, что вы делаете неправильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...