多图片下载 之 SDWebImage

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

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

主体思路

多图片下载 之 SDWebImage_第1张图片
主体思路

场景还原:

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

出现问题:

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

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

多图片下载 之 SDWebImage_第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;
}

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

多图片下载 之 SDWebImage_第3张图片
缓存图片

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

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参数图片

多图片下载 之 SDWebImage_第4张图片
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的图片最大尺寸(字节)
多图片下载 之 SDWebImage_第5张图片
图片最大尺寸(字节)
//无默认值,单位字节
[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) {

    }]

你可能感兴趣的:(多图片下载 之 SDWebImage)