12

我成功地将博客文章中的缩略图图像异步加载到我的 UITableView 中。

我遇到的问题是图像仅在我点击单元格或向下滚动时才会出现。

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

当我向下滚动时,图像会显示在单元格中它们应该显示的位置。

这是我的代码(我正在使用 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 中看到了这一点。

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

4

5 回答 5

12

在混合 asynch 和表时要注意的事情是 asynch 在将来的未知时间完成,可能是在单元格被滚动、删除、重用等之后。

此外,如果滚动该单元格,从网络上提取的图像也会丢失。不确定 AFNetworking 是否为您缓存,但最好不要假设。这是使用本机网络的解决方案:

// ...
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"];
}
// ...

现在,没有任何第三方帮助的严肃异步加载

- (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
            }
        }
    }];
}

为此,应将帖子创建为 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]];

或者,如果很难直接更改帖子模型,您可以设置另一个结构来缓存下载的图像。由 url 字符串键入的可变字典是一个很好的结构:

@property (nonatomic,strong) NSMutableDictionary *imageCache;
@synthesize imageCache=_imageCache;

// lazy init on the getter...

- (NSMutableDictionary *)imageCache {
    if (!_imageCache) {
        _imageCache = [NSMutableDictionary dictionary];
    }
    return _imageCache;
}

现在,在配置单元格时,通过检查缓存来查看是否有缓存的图像...

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

下载图像后,将其缓存...

// change to the asynchLoad: method I suggested
UIImage *image = [UIImage imageWithData:data];
[self.imageCache setValue:image forKey:urlString];
于 2012-09-29T20:41:16.353 回答
5

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

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

占位符需要具有与缩略图相似的尺寸比以避免变形。

于 2012-09-29T20:08:46.510 回答
2

我挠了很久,终于弄明白了。

我的错误是cell.imageView当我应该设置我的实际插座时,我设置了图像cell.eventImageView。它与UITableViewCell. 希望它可以帮助某人。

于 2014-12-05T16:13:58.467 回答
1

这是我的解决方案,使用 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
于 2012-10-24T07:04:31.497 回答
0

我参加聚会已经很晚了,但是如果您深入了解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];
于 2013-08-20T19:30:12.480 回答