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
Après sélection de la ligne
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;
}
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
Vous devez vous connecter pour publier un commentaire.
Vous devriez appeler
setNeedsLayout
sur la cellule après le réglage de la vignette.À partir de l'Apple Doc:
"Appeler cette méthode sur votre application thread principal lorsque vous souhaitez modifier la mise en page d'une vue de les sous-vues. Cette méthode prend note de la demande et retourne immédiatement. Parce que cette méthode ne permet pas de forcer une mise à jour immédiate, mais au lieu de cela attend pour le prochain cycle de mise à jour, vous pouvez l'utiliser pour invalider la disposition de plusieurs points de vue avant que l'un de ces points de vue sont mis à jour. Ce comportement vous permet de consolider l'ensemble de votre mise en page des mises à jour pour un cycle de mise à jour, ce qui est généralement mieux pour le spectacle."
Tu es la bienvenue, content que ça a fonctionné!
En fait, petite question: ne serait-il pas techniquement être mieux d'appeler [cellule setNeedsLayout]? Je lisais l'Apple doc pour layoutSubviews et c'est ce que j'ai trouvé: "Vous ne devez pas appeler cette méthode [layoutSubviews] directement. Si vous voulez forcer une mise à jour, appelez le setNeedsLayout méthode au lieu de le faire avant le prochain dessin de mise à jour." Qu'en pensez-vous? (à la fois fonctionnel de travail par la voie)
Ah, vous avez tout à fait raison, c'est ce que je voulais dire, c'était juste le fait d'aller trop vite là!
Merci pour rattraper mon erreur, et pour accepter la réponse!
OriginalL'auteur Carl Veazey
Une autre solution (et celui que j'ai utilisé pour cette mission) est d'appeler setNeedsDisplay sur la cellule de l'imageView une fois que vous avez affecté à l'UIImage pour que imageView.
Donc en gros, j'ai créé une catégorie appelée FlickrDownloader qui encapsule les fonctionnalités de FlickrFetcher (ainsi que mon code de mise en cache). FlickrDownloader a cette méthode:
C'est essentiellement un appel à la même fonction de FlickrFetcher, mais il ajoute un rappel des thats est appelé lors de l'achèvement de téléchargement de la photo. Dans le cas de la mise à jour de l'imageView de UITableViewCell le rappel ressemble à ceci:
(0,0,0,0)
? Quand j'ai essayé quelque chose de similaire, il n'a pas redimensionner jusqu'à ce que j'ai forcélayoutSubviews
à être appelé. Avez-vous été à l'aide d'une image d'espace réservé, peut-être?si vous appelez [cellule.imageView setNeedsDisplay], ne pas besoin de votre classe pour implémenter la méthode drawRect? Le contrôle de retour au cours de l'automne 2011 conférence 4 diapositive n ° 8, setNeedsDisplay met en place tout dans l'ordre d'appel drawRect. Il n'a pas vraiment dire si c'est plus ou moins que cela. n'est ce pas?
Vous avez raison, j'ai utilisé une image d'espace réservé comme le LazyTableImages exemple. Étant donné que c'était ma démarche depuis le début, peut-être que j'ai autour de réglage de l'image.
setNeedsDisplay indique le dessin des routines qui doit il est drawRect appelé. Le UIImageView classe possède une méthode drawRect... mais peut-être hérité d'une autre classe. Je crois que vous avez peut-être référence les étapes nécessaires pour mettre en œuvre une coutume drawRect pour la vue et à l'aide de setNeedsDisplay à cause que drawRect à être appelé.
OriginalL'auteur Scott H