Asynchrone UITableViewCell Chargement de l'Image en Utilisant le PGCD

Je suis en train d'essayer de charger une UITableView liste de Photo Flickr (cs193p iOS Stanford, l'attribution 5). Pour éviter de l'INTERFACE utilisateur de blocage, j'ai reporté la vignette de téléchargement de chaque cellule dans une autre file d'attente (mais ne mise à jour de l'INTERFACE utilisateur de retour dans la file d'attente principale). Ce code ne fonctionne pas de manière asynchrone de charger les images, bien que cela ne soit ajouter une vignette pour une fois que je clique sur le UITableViewCell ligne. (voir les captures d'écran ci-dessous). Toute idée de ce que je fais mal?

PS: j'ai regardé déjà dans quelques autres stackoverflow questions & Apple LazyTableImages exemple, mais je reste convaincu que c'est la façon la plus propre à atteindre le résultat souhaité.

Merci!

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Photo List Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    //Configure the cell
    NSDictionary *photo = [self.photoList objectAtIndex:indexPath.row];


    if (photo != nil) {
        if ([[photo objectForKey:@"title"] length] > 0) {
            cell.textLabel.text = [photo objectForKey:@"title"];
        } else if ([[[photo objectForKey:@"description"] objectForKey:@"_content"] length] > 0) {
            cell.textLabel.text = [[photo objectForKey:@"description"] objectForKey:@"_content"];
        } else {
            cell.textLabel.text = @"Unknown";
        }
    }
    cell.imageView.image = [[UIImage alloc] initWithCIImage:nil];

    //Fetch using GCD
    dispatch_queue_t downloadThumbnailQueue = dispatch_queue_create("Get Photo Thumbnail", NULL);
    dispatch_async(downloadThumbnailQueue, ^{
        UIImage *image = [self getTopPlacePhotoThumbnail:photo];
        dispatch_async(dispatch_get_main_queue(), ^{
            if ([self.tableView.visibleCells containsObject:cell]) {
                [cell.imageView setImage:image];
            }
        });
    });
    dispatch_release(downloadThumbnailQueue);

    return cell;
}

Avant de cliquer sur une ligne
Asynchrone UITableViewCell Chargement de l'Image en Utilisant le PGCD

Après sélection de la ligne
Asynchrone UITableViewCell Chargement de l'Image en Utilisant le PGCD

Mise à JOUR: Pour ceux qui sont intéressés, c'est le dernier code que j'ai utilisé:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  static NSString *CellIdentifier = @"Photo List Cell";
  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

  //Configure the cell
  NSDictionary *photo = [self.photoList objectAtIndex:indexPath.row];

  if (photo != nil) {
    if ([[photo objectForKey:@"title"] length] > 0) {
        cell.textLabel.text = [photo objectForKey:@"title"];
    } else if ([[[photo objectForKey:@"description"] objectForKey:@"_content"] length] > 0) {
        cell.textLabel.text = [[photo objectForKey:@"description"] objectForKey:@"_content"];
    } else {
        cell.textLabel.text = @"Unknown";
    }
  }
  cell.imageView.image = [[UIImage alloc] initWithCIImage:nil];

  //Fetch using GCD
  dispatch_queue_t downloadThumbnailQueue = dispatch_queue_create("Get Photo Thumbnail", NULL);
  dispatch_async(downloadThumbnailQueue, ^{
    UIImage *image = [self getTopPlacePhotoThumbnail:photo];
    dispatch_async(dispatch_get_main_queue(), ^{
        UITableViewCell *cellToUpdate = [self.tableView cellForRowAtIndexPath:indexPath]; //create a copy of the cell to avoid keeping a strong pointer to "cell" since that one may have been reused by the time the block is ready to update it. 
        if (cellToUpdate != nil) {
            [cellToUpdate.imageView setImage:image];
            [cellToUpdate setNeedsLayout];
        }
    });
  });
  dispatch_release(downloadThumbnailQueue);

  return cell;
}
Hey, ce qui est totalement hors sujet, mais vous vous demandez si à l'intérieur du bloc que vous envoyez sur le thread principal, au lieu de vérifier pour objet l'égalité entre les cell, vérifier si une cellule à indexPath existe?
J'ai juste essayé ceci: si ([self.tableView cellForRowAtIndexPath:indexPath] != nil) { ...etc } et il fonctionne très bien ainsi. Est-ce que vous aviez en tête?
Droit, et non pas à l'aide de cell.imageView directement dans votre bloc, mais plutôt de l'accaparement de la cellule à indexPath et l'utilisation de son image. Je pense que vous pourriez rencontrer des problèmes avec la cellule de réutiliser si vous utilisez cell directement la façon dont elle est définie à l'intérieur de votre thread principal bloc.
oui, vous avez raison! Le bloc de maintenir une forte pointeur vers la cellule, et ce sera d'ailleurs un problème que si il essaie de mettre à jour l'image d'une cellule qui est actuellement en cours de ré-utilisé pour une autre Photo de Flickr. Belle prise!

OriginalL'auteur sybohy | 2012-09-07