iOS UITableView中异步加载图片 - 解决方案

问题背景:

需要在UITableView中的每一行下载图片,之前使用placeholder,下载好后存在cache中。

解决方案:

方案一:

使用SDWebImage:https://github.com/rs/SDWebImage

如何安装及使用在git页面有详细解释,具体使用的代码:

#import <SDWebImage/UIImageView+WebCache.h>

...

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *MyIdentifier = @"MyIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

    if (cell == nil)
    {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier:MyIdentifier] autorelease];
    }

    // Here we use the new provided setImageWithURL: method to load the web image
    [cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
                   placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

    cell.textLabel.text = @"My Text";
    return cell;
}

方案二:

使用iOS自有的异步多线程,下载好图片后存入cache,再使用delegate函数更新tableview:

- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation

初始化:

@interface ViewController ()

@property (strong, nonatomic)  NSMutableArray *imageArray;
@property (strong, nonatomic) NSCache *imageCache;
@property (weak, nonatomic) IBOutlet UITableView *myCustomTableView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.imageCache = [[NSCache alloc] init];
}

TableView delegate函数:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Number of rows is the number of time zones in the region for the specified section.
    return 32;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"cellForRowAtIndexPath %d", indexPath.row);

    static NSString *MyIdentifier = @"customIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
    if (cell == nil) {
        cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault  reuseIdentifier:MyIdentifier];
    }

    if ([cell isKindOfClass:[CustomTableViewCell class]])
    {
        CustomTableViewCell *customCell = (CustomTableViewCell *)cell;
        NSData *imageData = [self.imageCache objectForKey:[NSString stringWithFormat:@"%d", indexPath.row]];

        if(imageData != nil){
            customCell.customImageView.image = [UIImage imageWithData:imageData];
        }
        else{
            customCell.customImageView.image = [UIImage imageNamed:@"test1"];

            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long) NULL), ^(void){
                UIImage *image = [self getPictureFromServer];

                if (image != nil) {
                    NSData *tmpImageData = UIImagePNGRepresentation(image);
                    [self.imageCache setObject:tmpImageData forKey:[NSString stringWithFormat:@"%d", indexPath.row]];
                    NSLog(@"download image for %d", indexPath.row);

                    [self performSelectorOnMainThread:@selector(reloadTableViewDataAtIndexPath:) withObject:indexPath waitUntilDone:NO];
                }
                else{
                    // do nothing ..
                }
            });
        }
    }
    else{
        // do nothing ..
    }

    return cell;
}

reloadTableViewDataAtIndexPath:

- (void) reloadTableViewDataAtIndexPath: (NSIndexPath *)indexPath{
    NSLog(@"MyWineViewController: in reload collection view data for index: %d", indexPath.row);

    NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil];
    [self.myCustomTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
//    [self.myCustomTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationAutomatic];
//    [self.myCustomTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationBottom];
//    [self.myCustomTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationLeft];
//    [self.myCustomTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationMiddle];
//    [self.myCustomTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationNone];
//    [self.myCustomTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationRight];
//    [self.myCustomTableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationTop];
}

下载图片

- (UIImage *) getPictureFromServer{
    UIImage *image = nil;
    NSString *urlString = [NSString stringWithFormat:@"http://yourPicture<span style="font-family: Arial, Helvetica, sans-serif;">.</span><span style="font-family: Arial, Helvetica, sans-serif;">jpg"];</span>

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:urlString]];
    [request setHTTPMethod:@"GET"];

    NSURLResponse *response;
    NSError *connectionError;
    NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&connectionError];

    if (connectionError == NULL) {
        NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
        NSLog(@"getPictureFromServer - Response Status code: %ld", (long)statusCode);

        if (statusCode == 200) {
            image = [UIImage imageWithData:returnData];
        }
        else{
            // do nothing..
        }
    }
    else{
        // do nothing..
    }

    return image;
}

方案三:(不推荐)

在方案二的基础上,变动在于下载好图片后load整个tableview,缺点时会引起滑动tableview时阻塞。

- (void) reloadTableViewData{
    NSLog(@"MyWineViewController: in reload collection view data");
    [self.myCustomTableView reloadData];
}

参考链接:

http://stackoverflow.com/questions/15290974/uitableview-on-screen-image-download-lazy-loading

http://stackoverflow.com/questions/7040740/reload-spefic-uitableview-cell-ios

时间: 2024-12-19 09:42:12

iOS UITableView中异步加载图片 - 解决方案的相关文章

IOS中UITableView异步加载图片的实现

本文转载至 http://blog.csdn.net/enuola/article/details/8639404 最近做一个项目,需要用到UITableView异步加载图片的例子,看到网上有一个EGOImageView的很好的例子. 但是由于,EGOImageView的实现比较复杂,于是自己就动手做了一个AsynImageView,同样可以实现EGOImageView的效果. 而且自己写的代码比较清晰,容易理解,同样可以实现指定placehoderImage以及指定imageURL,来进行图片

ios UITableView 异步加载图片并防止错位

UITableView 重用 UITableViewCell 并异步加载图片时会出现图片错乱的情况 对错位原因不明白的同学请参考我的另外一篇随笔:http://www.cnblogs.com/lesliefang/p/3619223.html . 当然大多数情况下可以用 SDWebImage, 这个库功能强大,封装的很好.但自己重头来写可能对问题理解的更深. SDWebImage 有点复杂,很多人也会参考一下封装出一套适合自己的类库. 基本思路如下: 1 扩展(category) UIImage

Android中ListView异步加载图片错位、重复、闪烁问题分析及解决方案

Android中ListView异步加载图片错位.重复.闪烁问题分析及解决方案 我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位.重复.闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化. 比如ListView上有100个Item,一屏只显示10个Item,我们知道getView()中convertView是用来复用View对象的,因为一个Item的对应一个View对象,而ImageView控件就是View对象通

Android ListView异步加载图片乱序问题,原因分析及解决方案

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/45586553 在Android所有系统自带的控件当中,ListView这个控件算是用法比较复杂的了,关键是用法复杂也就算了,它还经常会出现一些稀奇古怪的问题,让人非常头疼.比如说在ListView中加载图片,如果是同步加载图片倒还好,但是一旦使用异步加载图片那么问题就来了,这个问题我相信很多Android开发者都曾经遇到过,就是异步加载图片会出现错位乱序的情况.遇到这个问题时,不

android listview异步加载图片错位,重复,闪烁分析以及解决方案

我们在使用listview异步加载图片 的时候,在快速滑动或者网络不好的情况下,会出现图片错位,重复,闪烁等问题,其实这些问题总结起来就是一个问题, 比如listview上有100个item,一屏只显示10个item,我们知道getView()中converView是用来复用view对象的,因为一个item的view对象,而imageview控件就是view通过findViewById()获得的,而我们在复用view对象时,也就是说这个imageview也被复用了,比如第11个item的view

Android ListView异步加载图片错位、重复、闪烁分析以及解决方案

我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位.重复.闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化. 比如ListView上有100个Item,一屏只显示10个Item,我们知道getView()中convertView是用来复用View对象的,因为一个Item的对应一个View对象,而ImageView控件就是View对象通过findViewById()获得的,而我们在复用View对象时,同时这个Ima

Android之ListView异步加载图片且仅显示可见子项中的图片

折腾了好多天,遇到 N 多让人崩溃无语的问题,不过今天终于有些收获了,这是实验的第一版,有些混乱,下一步进行改造细分,先把代码记录在这儿吧. 网上查了很多资料,发现都千篇一律,抄来抄去,很多细节和完整实例都没看到,只有自己一点点研究了,总体感觉 android 下面要显示个图片真不容易啊. 项目主要实现的功能: 异步加载图片图片内存缓存.异步磁盘文件缓存解决使用 viewHolder 后出现的图片错位问题优化列表滚动性能,仅显示可见子项中的图片无需固定图片显示高度,对高度进行缓存使列表滚动时不会

iOS多线程自定义operation加载图片 不重复下载图片

摘要:1:ios通过抽象类NSOperation封装了gcd,让ios的多线程变得更为简单易用:   2:耗时的操作交给子线程来完成,主线程负责ui的处理,提示用户的体验   2:自定义operation继承自NSOperation,在子线程中下载图片: 3:保证图片只下载一次,还有保证下载任务不重复 ------------------------------------------------------------------------------------ 实现原理:1:图片缓存:用

cocos2dx lua中异步加载网络图片,可用于显示微信头像

最近在做一个棋牌项目,脚本语言用的lua,登录需要使用微信登录,用户头像用微信账户的头像,微信接口返回的头像是一个url,那么遇到的一个问题就是如何在lua中异步加载这个头像,先在引擎源码里找了下可能会提供这个功能的地方,发现好像没有提供类似功能,那么只能自己动手写.所以我在ImageView这个类里面添加了一个成员方法,其实可以不写在ImageView里,而且我觉得非必需情况下还是不要修改引擎源码的好,因为如果源码改动比较多的话,将来引擎版本升级会比较麻烦.我写在ImageView里纯粹是想偷