点击或滚动后,asynchronous下载的图像只出现在UITableView中

我成功地从博客文章加载我的UITableViewasynchronous缩略图。

我遇到的问题是,只有当我点击单元格或向下滚动时才会显示图像。

当我点击单元格时,图像出现在左侧,将标题和字幕推向右侧。

当我向下滚动时,图像出现在细胞应该显示的位置。

这是我的代码(我正在使用AFNetworking):

#import "UIImageView+AFNetworking.h" - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return posts.count; } - (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]; } NSDictionary *post = [posts objectAtIndex:indexPath.row]; NSString *postpictureUrl = [post objectForKey:@"picture"]; [cell.imageView setImageWithURL:[NSURL URLWithString:postpictureUrl]]; cell.textLabel.text = [post objectForKey:@"post_text"]; cell.detailTextLabel.text = [post objectForKey:@"post_author_name"]; return cell; } 

我在iPhone 6.0模拟器,XCode 4.5,OSX MtLion中看到了这一点。

任何想法为什么图像不是在初始屏幕上绘制?

混合asynchronous和表格时,要注意的一点是,asynchronous在未来的未知时间完成,可能在单元格被滚动,移除,重用等之后。

而且,如果该单元格被滚动,则从网上获取的图像将会丢失。 不知道AFNetworking是否为你caching,但不要假设。 这是一个使用本地networking的解决scheme:

 // ... NSDictionary *post = [posts objectAtIndex:indexPath.row]; NSString *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"]; } // ... 

现在,没有任何第三方的帮助,没有废话的asynchronous加载

 - (void)asynchLoad:(NSString *)urlString forIndexPath:(NSIndexPath *)indexPath { NSURL *url = [NSURL urlWithString:urlString]; 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 } } }]; } 

为了这个工作,post应该创build为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]]; 

或者,如果很难直接更改post模型,则可以设置另一个结构来caching下载的图像。 由urlstring键入的可变字典是一个很好的结构使用:

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

现在,在configuration单元格时,通过检查caching来查看是否有caching的图像。

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

一旦图像下载,caching…

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

这个问题通过在这一行中放置一个占位符来解决

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

占位符需要具有与缩略图类似的尺寸比率以避免失真。

我挠了挠头,终于弄清楚了。

我的错误是,我设置图像在cell.imageView当我应该设置我的实际出口cell.eventImageView 。 这是在UITableViewCell提供的通用imageview搞乱。 希望它有助于某人。

这是我的解决scheme,使用UIImageView类别。
注意:因为我们在第一行中执行self.image = nil,所以调用此方法后,必须为cell.ImageView设置一个占位符图像。

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

和类别:

 #import "UIImageView+AsyncLoad.h" @implementation UIImageView (AsyncLoad) - (void)loadImageForURLString:(NSString *)imageUrl { self.image = nil; [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString: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 

我很晚了,但如果你深入了解UIImageView + AFNetworking文档,你会发现这个方法– setImageWithURLRequest:placeholderImage:success:failure:当图像可用时,你可以使用它重新加载单元格:

 NSURLRequest *urlRequest = [NSURLRequest requestWithURL: [NSURL URLWithString: 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];