码迷,mamicode.com
首页 > 移动开发 > 详细

iOS开发之网络图片缓存

时间:2015-11-25 00:24:18      阅读:254      评论:0      收藏:0      [点我收藏+]

标签:

    问题一:如果使用同步下载,那么网速慢的时候会超级卡

 

    问题二:图片没有frame,所以cell初始化的时候,给imageView的frame是0,异步下载完成之后不显示

    解决办法:使用占位图(如果占位图比较大,自定义cell可以解决)

    cell重用的时候重复多次下载的问题:控制器跳过了模型,直接对view赋值

 

    问题四:在用户快速滚动的时候,会重复添加下载操作到队列

    解决办法:建立一个下载操作的缓冲池,首先检查"缓冲池"里是否有当前图片下载操作,如果有,就不在创建了,保证一个图片只对应一个下载操作

    将图像保存到模型里优缺点

    优点:不用重复下载,利用MVC刷新表格,不会造成数据混乱,加载数据比较快

    缺点:内存:所有下载好的图像都会记录在模型里。如果数据比较多(2000个)

    造成内存警告

 

    -- *图像跟模型耦合性太强,导致清理内存非常困难

    解决办法:模型跟图像分开,在控制器里做缓存

 

    问题6:下载操作缓存池,会越来越大,想办法清理

@interface ViewController ()

//数据源
@property (nonatomic, strong) NSArray *dataList;
//管理全局下载操作队列
@property (nonatomic, strong) NSOperationQueue *opQueue;

//所有下载操作的缓冲池 (key:当前图片的url,value下载操作)
@property (nonatomic, strong) NSMutableDictionary *operationCache;

//所有图片在内存中的缓存
@property (nonatomic, strong) NSCache *imgCache;

@end

- (NSCache *)imgCache {
    if (!_imgCache) {
        _imgCache = [[NSCache alloc] init];
        _imgCache.countLimit = 10;
    }
    return _imgCache;
}

- (NSMutableDictionary *)operationCache {
    if (!_operationCache) {
        _operationCache = [NSMutableDictionary dictionary];
    }
    return _operationCache;
}

- (NSOperationQueue *)opQueue  {
    if (_opQueue == nil) {
        _opQueue = [[NSOperationQueue alloc] init];
    }
    return _opQueue;
}

- (NSArray *)dataList {
    if (!_dataList) {
        NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil]];
        //字典转模型
        NSMutableArray *mulArr = [NSMutableArray array];
        for (NSDictionary *dict in array) {
            [mulArr addObject:[AppModel appWithDict:dict]];
        }
        _dataList = mulArr;
    }
    return _dataList;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.dataList.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ID];
    }
    AppModel *app = self.dataList[indexPath.row];
    cell.textLabel.text = [app name];
    cell.detailTextLabel.text = [app download];
    
    //判断模型里面是否有图像
    if ([self.imgCache objectForKey:app.icon]) {//如果模型里面有头像直接赋值
        cell.imageView.image = [self.imgCache objectForKey:app.icon];
    }
    else {
        //显示图片
        //如果沙盒里面有图片,直接从沙盒加载
        UIImage *image = [UIImage imageWithContentsOfFile:[self cachePathWithUrl:app.icon]];
        if (image) {
            //设置图片缓存到内存,方便下次从内存直接加载
            [self.imgCache setObject:image forKey:app.icon];
            
            //显示图片到cell
            cell.imageView.image = [self.imgCache objectForKey:app.icon];
        }
        else {//沙盒里面没有图片,显示占位图,网上下载
            cell.imageView.image = [UIImage imageNamed:@"user_default"];
            //下载图片
            [self downLoadImg:indexPath];
        }
    }
    return cell;
}

- (void)downLoadImg:(NSIndexPath *)indexPath {
    AppModel *app = self.dataList[indexPath.row];
    //如果下载缓冲池里面有当前图片的下载操作,就不用创建下载操作,没有才去创建操作
    //判断缓冲池中是否存在当前图片的操作
    if ([self.operationCache valueForKey:app.icon]) {
        NSLog(@"正在玩命下载中...");
    }
    else {
        //没有下载操作
        //异步下载图片,直接return cell不需要等待
        NSBlockOperation *downloadOp = [NSBlockOperation blockOperationWithBlock:^{
            //模拟延时
//            if (indexPath.row == 6) {
//                [NSThread sleepForTimeInterval:5];
//            }
            [NSThread sleepForTimeInterval:0.5];
            //            NSLog(@"正在下载中...");
            //下载图片(二进制)
            NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]];
            UIImage *image = [UIImage imageWithData:data];
            
            //将下载好的数据保存到模型
            //字典的赋值不能为nil
            if (image) {
                [self.imgCache setObject:image forKey:app.icon];
                
                //将图片写入沙盒
                [data writeToFile:[self cachePathWithUrl:app.icon] atomically:YES];
                
                //将操作从操作缓冲池删除
                [self.operationCache removeObjectForKey:app.icon];
            }
            
            //更新UI,应该回到主线程
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                //只设置了image,没有frame,调用layoutSubView()才会给子控件重新布局
                //选中某行cell,也会触发layoutSubViews()方法,会给子视图重新布局
                //            cell.imageView.image = image;
                //刷新当前行(会重新调用初始化方法,重新判断模型里面是否有图像,有的话直接显示)
                [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
            }];
        }];
        [self.opQueue addOperation:downloadOp];
        NSLog(@"------%li",self.opQueue.operationCount);
        
        //将操作添加到缓存池(使用图片的url作为key)
        [self.operationCache setValue:downloadOp forKey:app.icon];
    }
}

#pragma mark - 在真实开发中,一定要注意这个方法
   
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    //需要在这里做一些内存清理工作,如果不处理,会被系统强制杀死(闪退)
    //清理图片缓存
    [self.imgCache removeAllObjects];
    
    //清理操作缓存
    [self.operationCache removeAllObjects];
    
    //取消下载队列里面的任务
    [self.opQueue cancelAllOperations];
}

#pragma mark - 拼接一个文件在沙盒的全路径
- (NSString *)cachePathWithUrl:(NSString *)urlString {
    //获得缓存的路径
    NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    
    //把路径跟uslString拼接起来
    return [cachePath stringByAppendingPathComponent:urlString.lastPathComponent];
}


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"%@",self.operationCache);
//    for (AppModel *app in self.dataList) {
//        NSLog(@"==========%@",[self.imgCache valueForKey:app.icon]);
//    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 100;
}

- (void)dealloc {
    NSLog(@"dealloc");
}

 

iOS开发之网络图片缓存

标签:

原文地址:http://www.cnblogs.com/wuhongxing/p/4993402.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!