下载异步只出现在UITableView的图片请点击或滚动后 [英] Images downloaded asynchronously only appear in UITableView after tap or scroll

查看:139
本文介绍了下载异步只出现在UITableView的图片请点击或滚动后的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我成功加载从博客帖子异步缩略图到我的UITableView。

I am successfully loading thumbnail images from blog posts asynchronously into my UITableView.

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

The issue I'm having is that the images only appear if I tap the cell OR if I scroll down.

当我点击的单元格,图像出现在左侧,推标题和副标题的权利。

When I tap the cell, the image appears on the left, pushing the Title and Subtitle to the right.

当我向下滚动,图像显示在它们应该在的细胞,因为它们显现出来。

When I scroll down, the images appear where they should in the cells as they are revealed.

下面是我的code(我使用AFNetworking):

Here's my code (I'm using 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的模拟器,X code ++ 4.5,OSX MtLion。

I am seeing this in the iPhone 6.0 simulator, XCode 4.5, OSX MtLion.

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

Any ideas why the images are not drawn on the initial screen?

推荐答案

您想知道混合非同步和表时的一点是,非同步完成在未来一个未知的时间,细胞滚动离开可能后,除去,再利用等。

The thing you want to be aware of when mixing asynch and tables is that the asynch finishes at an unknown time in the future, possibly after the cell is scrolled away, removed, reused, etc.

此外,该会从网上拉到形象,如果该单元格滚动离开丢失。不知道AFNetworking缓存你,但它可能是最好不要承担。下面是使用本机联网解决方案:

Also, the image that gets pulled from the web is lost if that cell is scrolled away. Not sure if AFNetworking caches for you, but it might be better to not assume. Here's a solution using native networking:

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

现在,没有任何第三方的帮助,没有废话非同步负载

Now, a no-nonsense asynch load without any 3rd party help

- (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 ...

For this to work, the posts should be created as 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字符串键入一个可变的字典是一个很好用的结构:

Alternatively, if it's hard to change the posts model directly, you can setup another structure to cache the downloaded images. A mutable dictionary keyed by the url strings is a good structure to use:

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

// lazy init on the getter...

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

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

Now, when configuring the cell, see if there's a cached image by checking the cache...

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

和图像被下载,它缓存...

And once an image is downloaded, cache it...

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

这篇关于下载异步只出现在UITableView的图片请点击或滚动后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆