点击或滚动后,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];
- 在iOS 5中使用平静的Web服务
- 使stringWithContentsOfURLasynchronous – 是否安全?
- Swift,从asynchronous块返回值
- 如何包装一个asynchronous方法,它将一个块转换为同步的目标c
- 即使在dispatch_async上,UILabel也不会更新
- 如何在没有达到全球GCD限制的情况下并行执行许多(100+)任务?
- 只有在asynchronous函数完成执行后才能运行代码
- iOS中的NSOperation – 如何处理循环和嵌套的NSOperation调用来获取图像
- 如何在asynchronous块内为dispatch_group_async调度dispatch_group_wait