多图片下载 之 SDWebImage

首先先了解一下我们多图片下载的一般解决方案

注:以下模拟AppStore浏览购买项目场景

主体思路

主体思路

场景还原:

进入app,当图片还没显示完成时,我们不停的拖拽tableview,就会不停的调用 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath. 导致以下俩个问题.

出现问题:

  1. 重复下载操作
  2. cell重用导致图片错位
    第一次进入app我们会进行下载图片,由于下载图片是一个耗时操作,此时用户进行拖拽,由于cell的重用机制移出屏幕的cell会被重用,之前的cell会被重用到下方,恰巧图片又刚好下载完成,这时候如果我们任然进行显示
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
    cell.imageView.image = image;
 }];

就会出现 --- 植物大战僵尸2 捕鱼 都出现了错乱

cell重用导致错乱

解决办法:

1.为了防止图片下载操作重复,我们将对应的操作对象做记录,无论是成功还是失败最后我们都移除该对象,保证操作的唯一性.

/** 内存缓存的图片 */
@property (nonatomic, strong) NSMutableDictionary *images;

/** 所有的操作对象 */
@property (nonatomic, strong) NSMutableDictionary *operations;

2.下载完成我们去刷新对应的cell

// 回到主线程显示图片
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
     [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}];

整体实现代码

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"app";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    XMGApp *app = self.apps[indexPath.row];
    cell.textLabel.text = app.name;
    cell.detailTextLabel.text = app.download;

    // 先从内存缓存中取出图片
    UIImage *image = self.images[app.icon];
    if (image) { // 内存中有图片,显示图片
        cell.imageView.image = image;
    } else {  // 内存中没有图片,检查沙盒中是否有图片

        // 获得Library/Caches文件夹
        NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
        // 获得文件名
        NSString *filename = [app.icon lastPathComponent];
        // 计算出文件的全路径
        NSString *file = [cachesPath stringByAppendingPathComponent:filename];
        // 加载沙盒的文件数据
        NSData *data = [NSData dataWithContentsOfFile:file];

        if (data) { // 沙盒中有图片,直接利用沙盒中图片
            UIImage *image = [UIImage imageWithData:data];
            cell.imageView.image = image;
            // 存到字典中
            self.images[app.icon] = image;
        } else { // 沙盒中没有图片,下载图片
            cell.imageView.image = [UIImage imageNamed:@"placeholder"];

            //查询是否有下载任务
            NSOperation *operation = self.operations[app.icon];
            if (operation == nil) { // 这张图片暂时没有下载任务
                operation = [NSBlockOperation blockOperationWithBlock:^{
                    // 下载图片
                    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]];
                    // 数据加载失败
                    if (data == nil) {
                        // 移除操作
                        [self.operations removeObjectForKey:app.icon];
                        return;
                    }

                    UIImage *image = [UIImage imageWithData:data];

                    // 存到字典中
                    self.images[app.icon] = image;

                    // 回到主线程显示图片
                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                        [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
                    }];

                    // 将图片文件数据写入沙盒中
                    [data writeToFile:file atomically:YES];
                    // 移除操作
                    [self.operations removeObjectForKey:app.icon];
                }];

                // 添加到队列中
                [self.queue addOperation:operation];

                // 存放到字典中
                self.operations[app.icon] = operation;
            }
        }
    }

    return cell;
}


小结:由于自己去完成多图片的下载 细节比较多,需要考虑cell重用错乱,重复下任务,网络错误data为空等等一系列的细节问题,为了提高开发效率我们通常会使用第三方框架


最终解决方案

第三方框架 SDWebImage

  • 导入头文件
#import "UIImageView+WebCache.h"
  • 加载图片设置占位图
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:app.icon] placeholderImage:[UIImage imageNamed:@"placeholder"]];

对照

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"app";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    XMGApp *app = self.apps[indexPath.row];
    cell.textLabel.text = app.name;
    cell.detailTextLabel.text = app.download;

    //只需要一句话
    [cell.imageView sd_setImageWithURL:[NSURL URLWithString:app.icon] placeholderImage:[UIImage imageNamed:@"placeholder"]];

    return cell;
}

而且它也帮我们完成了缓存的处理

缓存图片

让我们简单的了解一下如何使用这个强大的第三方框架

1.下面我们以参数较多的方法举例:

 [cell.imageView sd_setImageWithURL:[NSURL URLWithString:app.icon] placeholderImage:[UIImage imageNamed:@"placeholder"] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) {
        // expectedSize: 图片的总字节数
        // receivedSize: 已经接收的图片字节数

        NSLog(@"下载进度:%f", (double)receivedSize / expectedSize);
    } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
        NSLog(@"下载完图片");
    }];

1,sd_setImageWithURL获取网络图片
2,placeholderImage占位图片
3,progress 下载进度 用法: NSLog(@"下载进步:%f",(double)receivedSize / expectedSize);
4, *image *error *imageURL分别完成后返回 的图片,错误和下载地址
5,SDImageCacheType cacheType 是枚举类型,图片存储位置在内存、磁盘或无
6,SDWebImageOptions 枚举类型
    用法:SDWebImageOptions options = SDWebImageRetryFailed | SDWebImageLowPriority
    SDWebImageRetryFailed 下载失败重复下载        常用
    SDWebImageLowPriority 当UI交互的时候暂停下载   常用
    SDWebImageCacheMemoryOnly 只存图片在内存
    SDWebImageProgressiveDownload 可以像浏览器那样从上往下下载刷新图片
    SDWebImageRefreshCached 刷新缓存
    SDWebImageHighPriority  高优先级
    SDWebImageDelayPlaceholder 不加载占位图

options参数图片

options参数图片

2.内存处理

因为SDWebImgae是属于整个项目,不是属于某个控制器,所以不要在控制器里的didReceiveMemoryWarning处理内存问题,而且在AppDelegate.m添加applicationDidReceiveMemoryWarning方法

  • AppDelegate中 (√)
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
    // 取消所有下载
    [[SDWebImageManager sharedManager] cancelAll];
    // 清除内存缓存
    [[SDWebImageManager sharedManager].imageCache clearMemory];
}
  • 当前控制器中 出现内存警告(×)
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    self.images = nil;
    self.operations = nil;
    [self.queue cancelAllOperations];
}

3.其他功能

  • SDWebImage的图片缓存周期是多长:1个星期
默认缓存周期1周
//设置100天,默认是7天
[SDWebImageManager sharedManager].imageCache.maxCacheAge = 100 * 24 * 60 * 60
  • SDWebImage的图片最大尺寸(字节)
图片最大尺寸(字节)
//无默认值,单位字节
[SDWebImageManager sharedManager].imageCache.maxCacheSize = ;

拓展:只下载图片不设置 --- 给Button设置图片时可以使用

[[SDWebImageManager sharedManager] downloadImageWithURL:<#(NSURL *)#> options:<#(SDWebImageOptions)#> progress:^(NSInteger receivedSize, NSInteger expectedSize) {

    } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {

    }]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • SDWebImage托管在github上。https://github.com/rs/SDWebImage 这个类...
    XLsn0w阅读 698评论 0 0
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,121评论 29 470
  • 痴女阿三(上) 从楼上往下看,对面的小院里有一畦菜园,刚被松了土,墙根下挤挤挨挨的...
    欣雅_47ff阅读 683评论 1 4
  • Android中提供了View进行绘图处理,View可以满足大部分的绘图需求,但是有时候,View却显得力不从心,...
    冰鉴IT阅读 84,052评论 19 158