//
// ViewController.m
// 06-表格图片下载
//
// Created by jerry on 15/9/7.
// Copyright (c) 2015年 jerry. All rights reserved.
//
/**
* 代码重构
*
* 目的:1.如果代码太长,如果有一部分专门解决某一个问题,就单拿出来
* 写的时候,如果思路清晰,能够一次性写完,但是也要注意重构
* 时间长了,不好阅读
* 重构代码,便于维护
*
* 重构的方法:
* 如果有一部分代码专门解决某一个问题 ,就单拿出来
* 1.新建一个方法-->单一功能拿出来
* 2.参数-->需要传参数
* 3.在原来的代码地方调用,抽取的方法。
* 4.注意测试。
* 5.注意if嵌套,在实际开发中,非常忌讳很深的嵌套,能优化的话最好优化,
*/
#import "ViewController.h"
#import "ZPApp.h"
@interface ViewController ()
// PLIST 文件数据容器
@property(nonatomic,copy)NSArray *appList;
// 全局队列
@property(nonatomic,strong)NSOperationQueue *opQueue; // 缓冲池 所有下载操作的缓冲池
@property(nonatomic,strong)NSMutableDictionary *operationCache;
// 所有图片的缓存
@property(nonatomic,strong)NSMutableDictionary *imageCache;
@end @implementation ViewController -(NSMutableDictionary *)imageCache
{
if (_imageCache == nil) {
_imageCache = [NSMutableDictionary dictionary];
}
return _imageCache;
} -(NSMutableDictionary *)operationCache
{
if (_operationCache == nil) {
_operationCache = [NSMutableDictionary dictionary];
}
return _operationCache;
}
-(NSOperationQueue *)opQueue
{
if (_opQueue == nil) {
_opQueue = [[NSOperationQueue alloc]init];
}
return _opQueue;
} -(NSArray *)appList
{
if (_appList == nil) {
//获取文件路径
NSString *str = [[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
NSArray *fileArray = [NSArray arrayWithContentsOfFile:str];
NSMutableArray *muArray = [NSMutableArray array];
for ( NSDictionary *dict in fileArray) {
ZPApp *app = [ZPApp appWithDict:dict];
[muArray addObject:app];
}
_appList = muArray;
}
return _appList;
} -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.appList.count;
}
/**
* CELL里面的imageview属于懒加载
* 问题1:如果网络比较慢,会比较卡
* 解决办法:用异步下载
*
* 问题2:imageview没有frame
* 解决办法:使用一个占位图,异步下载完成以后,不显示。(如果占位图比较大,自定义cell)
*
* 问题3:如果图片下载速度不一致,同时用户浏览快速滚动的时候,会因为cell的重用导致图片混乱。
* 解决办法:MVC使用模型保持下载图像。再次刷新表格
*
* 问题4:在用户快速滚动的时候会重复添加下载操作到队列里。
* 解决办法:建立一个下载操作的缓冲池,首先检查缓冲池里是否有当前这个下载操作,有的话就不用创建,没有的时候在下载。保证一个图片只对应一个下载操作。
*
* 问题5:将图像保存到模型里有缺点:
* 优点:不用重复下载,利用mvc刷新表格,不会造成数据混乱。加载速度比较快
* 缺点:内存消耗比较大,因为所有下载好的图像都会记录在模型里。如果数据比较多(20000),就会造成很大的内存警告
*
* 问题6:图像跟模型耦合性太强,导致清理内存非常困难
* 解决办法:模型根图像分开,在控制器里边做缓存。
*
* 问题7:下载操作缓冲池,会越来越大,想办法清理
* 解决办法:
*/
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 创建cell的标识
static NSString *ID = @"AppCell";
// 查找缓存池中有没有标识为ID的cell 如果有直接拿来用 如果没有创建一个
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ID];
}
// 给cell 设置数据
ZPApp *app = self.appList[indexPath.row];
cell.textLabel.text = app.name;
cell.detailTextLabel.text = app.download;
// 判断模型里边是否有图像
if ([self.imageCache objectForKey:app.icon]) { // --如果模型里面有图像,直接给cell的imageview赋值。
NSLog(@"none");
// cell.imageView.image = app.image;
cell.imageView.image = self.imageCache[app.icon];
}else{
// 下载图片
// [NSThread sleepForTimeInterval:0.5];
// NSLog(@"正在下载.....");
// 现实占位图
cell.imageView.image = [UIImage imageNamed:@"user_default"];
#warning 从这里开始剪的代码
// 下载图片
[self downloadImage:indexPath];
}
// 异步执行下载,不需要等待,会直接执行return cell 也就是先初始化一个没有图片的cell 在表格上现实,后来把图片下载完成以后,给cell的imageview属性重新赋值。
return cell;
}
/**
* 下载图片
*
* @param indexPath <#indexPath description#>
*/
- (void)downloadImage:(NSIndexPath *)indexPath
{
ZPApp *app = self.appList[indexPath.row];
// 如果下载缓冲池里面有当前图片的下载操作,就不用创建下载操作,没有的话才需要 创建下载操作
#warning 缓冲池中的字典创建 key:是图片的url地址,因为这个地址是唯一的,而且是明确的。value:下载操作
if (self.operationCache[app.icon]) {
NSLog(@"已加入缓冲池,正在玩命下载中。。。");
return;
}
// 缓冲池没有下载操作。 // 异步下载图片
NSBlockOperation *downloadOp = [NSBlockOperation blockOperationWithBlock:^{
// 1.下载图片(二进制)
NSURL *url = [NSURL URLWithString:app.icon];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [UIImage imageWithData:data];
// app.image = img; // 把下载好的图片保存到模型。
// 字典的赋值不能为nil,
// 将下载好的数据保存到集合里
if (img) {
[self.imageCache setObject:img forKey:app.icon];
}
// 将操作从操作缓冲池删除
[self.operationCache removeObjectForKey:app.icon];
// 更新ui
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
// cell.imageView.image = app.image;
// 刷新当前行 reload会重新调用cell的初始化方法。重新判断模型里面是否有图像,有的话直接显示
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}];
}];
[self.opQueue addOperation:downloadOp];
// 将当前图片的下载操作,存放到缓冲池中。
[self.operationCache setObject:downloadOp forKey:app.icon];
}
/**
* 真正开发中一定要注意这个方法
*/
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
//当给了内存警告之后,一定要在这里做些内存清理的操作,如果不处理程序直接会被系统强制退出。
// 清理图片内存
[self.imageCache removeAllObjects];
// 清理操作缓冲
[self.operationCache removeAllObjects];
// 取消下载队列里的人物
[self.opQueue cancelAllOperations];
}
@end

model  .h

//
// ZPApp.h
// 06-表格图片下载
//
// Created by jerry on 15/9/7.
// Copyright (c) 2015年 jerry. All rights reserved.
//
// xcode 6 pch
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface ZPApp : NSObject
@property(nonatomic,copy)NSString *name;
@property(nonatomic,copy)NSString *icon;
@property(nonatomic,copy)NSString *download;
//@property(nonatomic,strong) UIImage *image;
+(instancetype)appWithDict:(NSDictionary *)dict; @end

.m

//
// ZPApp.m
// 06-表格图片下载
//
// Created by jerry on 15/9/7.
// Copyright (c) 2015年 jerry. All rights reserved.
// #import "ZPApp.h" @implementation ZPApp
+(instancetype)appWithDict:(NSDictionary *)dict
{
ZPApp *app = [[self alloc]init];
[app setValuesForKeysWithDictionary:dict];
return app;
}
@end

plist文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>name</key>
<string>植物大战僵尸</string>
<key>icon</key>
<string>http://p16.qhimg.com/dr/48_48_/t0125e8d438ae9d2fbb.png</string>
<key>download</key>
<string>10311万</string>
</dict>
<dict>
<key>name</key>
<string>捕鱼达人2</string>
<key>icon</key>
<string>http://p19.qhimg.com/dr/48_48_/t0101e2931181bb540d.png</string>
<key>download</key>
<string>9982万</string>
</dict>
<dict>
<key>name</key>
<string>保卫萝卜</string>
<key>icon</key>
<string>http://p17.qhimg.com/dr/48_48_/t012d281e8ec8e27c06.png</string>
<key>download</key>
<string>8582万</string>
</dict>
<dict>
<key>name</key>
<string>找你妹</string>
<key>icon</key>
<string>http://p18.qhimg.com/dr/48_48_/t0184f949337481f071.png</string>
<key>download</key>
<string>5910万</string>
</dict>
<dict>
<key>name</key>
<string>水果忍者</string>
<key>icon</key>
<string>http://p17.qhimg.com/dr/48_48_/t015f10076f95e27e74.png</string>
<key>download</key>
<string>5082万</string>
</dict>
<dict>
<key>name</key>
<string>鳄鱼小顽皮</string>
<key>icon</key>
<string>http://p16.qhimg.com/dr/48_48_/t01885f5596e1d30172.png</string>
<key>download</key>
<string>3918万</string>
</dict>
<dict>
<key>name</key>
<string>神偷奶爸</string>
<key>icon</key>
<string>http://p19.qhimg.com/dr/48_48_/t0164ad383c622aabef.png</string>
<key>download</key>
<string>3681万</string>
</dict>
<dict>
<key>name</key>
<string>时空猎人</string>
<key>icon</key>
<string>http://p17.qhimg.com/dr/48_48_/t017bc3cfcf3981b197.png</string>
<key>download</key>
<string>3645万</string>
</dict>
<dict>
<key>name</key>
<string>愤怒的小鸟</string>
<key>icon</key>
<string>http://p18.qhimg.com/dr/48_48_/t012fea7312194537c2.png</string>
<key>download</key>
<string>3552万</string>
</dict>
<dict>
<key>name</key>
<string>滑雪大冒险</string>
<key>icon</key>
<string>http://p18.qhimg.com/dr/48_48_/t01e61cbba53fb9eb82.png</string>
<key>download</key>
<string>3487万</string>
</dict>
<dict>
<key>name</key>
<string>爸爸去哪儿</string>
<key>icon</key>
<string>http://p18.qhimg.com/dr/48_48_/t0108c33d3321352682.png</string>
<key>download</key>
<string>3117万</string>
</dict>
<dict>
<key>name</key>
<string>我叫MT </string>
<key>icon</key>
<string>http://p17.qhimg.com/dr/48_48_/t01077fd80ffb5c8740.png</string>
<key>download</key>
<string>2386万</string>
</dict>
<dict>
<key>name</key>
<string>3D终极狂飙</string>
<key>icon</key>
<string>http://p17.qhimg.com/dr/48_48_/t01f55acd4a3ed024eb.png</string>
<key>download</key>
<string>2166万</string>
</dict>
<dict>
<key>name</key>
<string>杀手2</string>
<key>icon</key>
<string>http://p16.qhimg.com/dr/48_48_/t018f89d6e0922f75a1.png</string>
<key>download</key>
<string>1951万</string>
</dict>
<dict>
<key>name</key>
<string>俄罗斯方块</string>
<key>icon</key>
<string>http://p0.qhimg.com/dr/48_48_/t0183a670f1dbff380f.png</string>
<key>download</key>
<string>1290万</string>
</dict>
<dict>
<key>name</key>
<string>刀塔传奇</string>
<key>icon</key>
<string>http://p16.qhimg.com/dr/48_48_/t01c3f62a27c3de7af5.png</string>
<key>download</key>
<string>1249万</string>
</dict>
</array>
</plist>

cell下载图片的思路 --无沙盒(内存)缓冲的更多相关文章

  1. 【项目】用CIFilter得到图片没办法保存到沙盒里面,显示是CGImage为空

    错误代码: if (iOS9) { CGImageRef cgImage = [[CIContext new] createCGImage:outputImage fromRect:outputIma ...

  2. ios -- cell的图片下载

    1.面试题 1> 如何防止一个url对应的图片重复下载 * “cell下载图片思路 – 有沙盒缓存” 2> SDWebImage的默认缓存时长是多少? * 1个星期 3> SDWeb ...

  3. IOS 线程的总结(及cell的图片下载)

    零.线程的注意点(掌握) 1.不要同时开太多的线程(1~3条线程即可,不要超过5条)2.线程概念1> 主线程 : UI线程,显示.刷新UI界面,处理UI控件的事件2> 子线程 : 后台线程 ...

  4. iOS篇之有沙盒缓存

    内存指的就是主板上的存储部件,是CPU直接与之沟通,并用其存储数据的部件,存放当前正在使用的(即执行中)的数据和程序,它的物理实质就是一组或多组具备数据输入输出和数据存储功能的集成电路,内存只用于暂时 ...

  5. 三星手机使用应用沙盒一键修改路由mac数据

    之前文章介绍了怎么在安卓手机上安装激活xposed框架,xposed框架的极强的功能大家都知道,能够不修改apk的前提下,修改系统底层的参数,打比方在某些应用情景,大家需要修改手机的某个系统参数,这情 ...

  6. 魅族手机使用应用沙盒一键修改imsi数据

    较早前文章介绍了怎么在安卓手机上安装激活XPosed框架,XPosed框架的牛逼之处功能各位都介绍过,可以不修改apk的前提下,修改系统内核的参数,打比方在某些应用领域,各位需要修改手机的某个系统参数 ...

  7. 红米手机使用应用沙盒一键修改sdk信息

    前面文章介绍了怎么在安卓手机上安装激活XPOSED框架,XPOSED框架的极强的功能各位都介绍过,能不修改APK的前提下,修改系统内核的参数,打个比方在某些应用情景,各位需要修改手机的某个系统参数,这 ...

  8. IOS- 网络图片缓存到沙盒中 ,离线取出。

    一.缓存图片 //1.首先创建在沙盒中创建一个文件夹用于保存图片 NSFileManager *fileManager = [[NSFileManager alloc] init]; NSString ...

  9. java沙盒

    JAVA的安全模型不同于传统的安全方法,传统的安全方法中,大多数操作系统允许应用程序充分访问系统资源,在操作系统不提供安全保护的机器里,运行环境不能被信任.为了弥补这个缺陷,安全策略经常要求在应用程序 ...

随机推荐

  1. BZOJ2282 SDOI2011消防/NOIP2007树网的核(二分答案+树形dp)

    要求最大值最小容易想到二分答案.首先对每个点求出子树中与其最远的距离是多少,二分答案后就可以标记上一些必须在所选择路径中的点,并且这些点是不应存在祖先关系的.那么如果剩下的点数量>=3,显然该答 ...

  2. Python的二叉树实现

    二叉树需要实现的功能及思路 找到最小值 没什么好说的就是二叉树最左下的顶点 找到最大值 没什么好说的就是二叉树最右下的顶点 插入 分情况,如果二叉树为空那么直接直接设置成根节点就好了.否则就逐层向下, ...

  3. 【LOJ#10154】选课

    题目中所说的每门课都可能有先修课,也可能没有先修课,因此课与课之间的关系构成了一颗森林. 这种树上选择若干物品的最优解问题对应着树形背包问题. 阶段:子树的大小 状态:在当前子树中,选取 i 门课能够 ...

  4. 爬虫acm比赛成绩(多页成绩整合在一起、获取复制不了的数据)(hihocoder、计蒜客)

    https://github.com/congmingyige/web-crawler_rank-of-competition-in-JiSuanKe-and-hihocoder 1. 计蒜客(获取复 ...

  5. git 合并连续的几个 commits

    命令 git rebase -i HEAD~[N],如 git rebase -i HEAD~3 合并最近 3 个 commit. 运行上述界面后会进入一个编辑界面,快捷键是 vim 的快捷键. 修改 ...

  6. php redis在windows下的部署

    1.下载php扩展 下载地址:https://github.com/phpredis/phpredis/downloads 2.将下载php扩展redis放到php的ext目录下,然后在php.ini ...

  7. nginx 中配置多个location并解决js/css/jpg/等的加载问题

    2017-11-09 22:07 277人阅读 评论(0) 收藏 举报  分类: linux(1)  版权声明:如有版权问题,请私信我. ECS:阿里云 系统:ubuntu 16.04 我的配置文件位 ...

  8. 关于TCP连接状态的解释

    TCP各个状态主要存在于三次握手和四次挥手的过程 1.TCP建立连接时的三次握手: 服务端应用监听端口处于LISTEN状态,等待建立连接. 第一次握手:客户端发送SYN=一个随机数,然后进入SYN_S ...

  9. GBDT

    一.决策树分类 决策树分为两大类,分类树和回归树 分类树用于分类标签值,如晴天/阴天/雾/雨.用户性别.网页是否是垃圾页面 回归树用于预测实数值,如明天的温度.用户的年龄 两者的区别: 分类树的结果不 ...

  10. vue基础篇---路由的实现

    路由可以有两种实现方式,一种是标签形式的,一种是js实现. 标签: <router-link to='/city'> 北京 </router-link> 标签还有另外一种实现方 ...