Les images téléchargées de manière asynchronous n'apparaissent dans UITableView qu'après avoir tapé ou défiler

Je charge avec succès les images miniatures des articles de blog de manière asynchronous dans mon UITableView.

Le problème que j'ai est que les images n'apparaissent que si je touche la cellule OU si je défile vers le bas.

Lorsque je tape sur la cellule, l'image apparaît sur la gauche, en poussant le titre et le sous-titre vers la droite.

Quand je défile vers le bas, les images apparaissent où elles devraient dans les cellules comme elles sont révélées.

Voici mon code (j'utilise AFNetworking):

#import "UIImageView+AFNetworking.h" - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return posts.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSSsortingng *CellIdentifier = @"cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; } NSDictionary *post = [posts objectAtIndex:indexPath.row]; NSSsortingng *postpictureUrl = [post objectForKey:@"picture"]; [cell.imageView setImageWithURL:[NSURL URLWithSsortingng:postpictureUrl]]; cell.textLabel.text = [post objectForKey:@"post_text"]; cell.detailTextLabel.text = [post objectForKey:@"post_author_name"]; return cell; } 

Je vois cela dans le simulateur iPhone 6.0, XCode 4.5, OSX MtLion.

Des idées pour lesquelles les images ne sont pas dessinées sur l'écran initial?

La chose que vous voulez savoir quand vous mélangez asynch et tables est que l'asynch se termine à un moment inconnu dans le futur, peut-être après que la cellule ait été déplacée, enlevée, réutilisée, etc.

En outre, l'image extraite du Web est perdue si cette cellule est défilée. Vous ne savez pas si AFNetworking cache pour vous, mais il pourrait être préférable de ne pas supposer. Voici une solution utilisant le réseau natif:

 // ... NSDictionary *post = [posts objectAtIndex:indexPath.row]; NSSsortingng *postpictureUrl = [post objectForKey:@"picture"]; // find a place in your model, or add one, to cache an actual downloaded image UIImage *postImage = [post objectForKey:@"picture_image"]; if (postImage) { cell.imageView.image = postImage; // this is the best scenario: cached image } else { // notice how we don't pass the cell - we don't trust its value past this turn of the run loop [self asynchLoad:postpictureUrl forIndexPath:indexPath]; cell.imageView.image = [UIImage imageNamed:@"default"]; } // ... 

Maintenant, une charge d'asynch non-sens sans aucune aide de tiers

 - (void)asynchLoad:(NSSsortingng *)urlSsortingng forIndexPath:(NSIndexPath *)indexPath { NSURL *url = [NSURL urlWithSsortingng:urlSsortingng]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { if (!error) { // create the image UIImage *image = [UIImage imageWithData:data]; // cache the image NSDictionary *post = [posts objectAtIndex:indexPath.row]; [post setObject:image forKey:@"picture_image"]; // important part - we make no assumption about the state of the table at this point // find out if our original index path is visible, then update it, taking // advantage of the cached image (and a bonus option row animation) NSArray *visiblePaths = [self.tableView indexPathsForVisibleRows]; if ([visiblePaths containsObject:indexPath]) { NSArray *indexPaths = [NSArray arrayWithObject:indexPath]; [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation: UITableViewRowAnimationFade]; // because we cached the image, cellForRow... will see it and run fast } } }]; } 

Pour que cela fonctionne, les publications doivent être créées en tant que NSMutableDictionary …

 // someplace in your code you add a post to the posts array. do this instead. NSDictionary *postData = // however you get a new post [posts addObject:[NSMutableDictionary dictionaryWithDictionary:postData]]; 

Alternativement, s'il est difficile de changer directement le model des messages, vous pouvez configurer une autre structure pour mettre en cache les images téléchargées. Un dictionary modifiable avec les strings d'URL est une bonne structure à utiliser:

 @property (nonatomic,strong) NSMutableDictionary *imageCache; @synthesize imageCache=_imageCache; // lazy init on the getter... - (NSMutableDictionary *)imageCache { if (!_imageCache) { _imageCache = [NSMutableDictionary dictionary]; } return _imageCache; } 

Maintenant, lors de la configuration de la cellule, voir s'il y a une image caching en vérifiant le cache …

 // change to the cellForRowAtIndexPath method NSSsortingng *postpictureUrl = [post objectForKey:@"picture"]; UIImage *postImage = [self.imageCache valueForKey:postpictureUrl]; 

Et une fois qu'une image est téléchargée, cachez-la …

 // change to the asynchLoad: method I suggested UIImage *image = [UIImage imageWithData:data]; [self.imageCache setValue:image forKey:urlSsortingng]; 

Le problème est résolu en mettant un espace réservé dans cette ligne

 ... [cell.imageView setImageWithURL:[NSURL URLWithSsortingng:postpictureUrl] placeholderImage:[UIImage imageNamed:@"default"]]; .... 

L'espace réservé doit avoir un rapport de dimensions similaire à la vignette pour éviter la distorsion.

Je me suis gratté la tête longtime et j'ai finalement compris.

Mon erreur était que je définissais l'image dans cell.imageView quand je devrais être en train de définir ma sortie cell.eventImageView . Il jouait avec l'imageview générique fourni dans UITableViewCell . J'espère que ça aide quelqu'un.

C'est ma solution, en utilisant une catégorie pour UIImageView.
Remarque: puisque nous effectuons self.image = nil dans la première ligne, vous devez définir une image d'espace réservé pour la cellule. ImageView après avoir appelé cette méthode.

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ... [cell.imageView loadImageForURLSsortingng:row.imageUrl]; cell.imageView.image = tempImage; ... } 

et la catégorie:

 #import "UIImageView+AsyncLoad.h" @implementation UIImageView (AsyncLoad) - (void)loadImageForURLSsortingng:(NSSsortingng *)imageUrl { self.image = nil; [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithSsortingng:imageUrl]]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * response, NSData * data, NSError * error) { [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; if (data && self.window) { self.image = [UIImage imageWithData:data]; } }]; } @end 

Je suis assez en retard à la fête, mais si vous creusez un peu plus dans les docs UIImageView + AFNetworking, vous findez la méthode – setImageWithURLRequest:placeholderImage:success:failure: que vous pouvez utiliser pour recharger la cellule quand l'image est disponible :

 NSURLRequest *urlRequest = [NSURLRequest requestWithURL: [NSURL URLWithSsortingng: imageURL]]; __weak UITableViewCell *weakCell = cell; [cell.imageView setImageWithURLRequest: urlRequest placeholderImage: nil success: ^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { __strong UITableViewCell *strongCell = weakCell; strongCell.imageView.image = image; [tableView reloadRowsAtIndexPaths: @[indexPath] withRowAnimation: UITableViewRowAnimationNone]; } failure: NULL];