内存指的就是主板上的存储部件,是CPU直接与之沟通,并用其存储数据的部件,存放当前正在使用的(即执行中)的数据和程序,它的物理实质就是一组或多组具备数据输入输出和数据存储功能的集成电路,内存只用于暂时存放程序和数据,一旦关闭电源或发生断电,其中的程序和数据就会丢失。
  1 #import "ViewController.h"
  2 #import "CZApp.h"
  3 @interface ViewController ()
  4 // plist文件数据的容器
  5 @property (nonatomic, strong) NSArray *appList;
  6
  7 // 管理下载的全局队列
  8 @property (nonatomic, strong) NSOperationQueue *opQueue;
  9
 10 /**所有下载的缓冲池*/
 11 @property (nonatomic, strong) NSMutableDictionary *operationCache;
 12
 13 /**保存所有图像的缓存*/
 14 @property (nonatomic, strong) NSMutableDictionary *imageCache;
 15 @end
 16
 17
 18 @implementation ViewController
 19
 20 // 懒加载
 21 -(NSArray *)appList
 22 {
 23     if (_appList == nil) {
 24         NSArray *dicArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil]];
 25         // 字典转模型
 26         NSMutableArray *arryM = [NSMutableArray array];
 27         for(NSDictionary *dict in dicArray){
 28             CZApp *app = [CZApp appWithDict:dict];
 29             [arryM addObject:app];
 30         }
 31         _appList = arryM;
 32     }
 33     return _appList;
 34 }
 35
 36 -(NSOperationQueue *)opQueue
 37 {
 38     if (_opQueue == nil) {
 39         _opQueue = [[NSOperationQueue alloc] init];
 40     }
 41     return _opQueue;
 42 }
 43
 44 -(NSMutableDictionary *)operationCache
 45 {
 46     if (_operationCache == nil) {
 47         _operationCache = [[NSMutableDictionary alloc] init];
 48     }
 49     return _operationCache;
 50 }
 51
 52 -(NSMutableDictionary *)imageCache
 53 {
 54     if (_imageCache == nil) {
 55         _imageCache = [[NSMutableDictionary alloc] init];
 56     }
 57     return _imageCache;
 58 }
 59
 60 #pragma mark - 实现数据源方法
 61 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 62 {
 63     return self.appList.count;
 64 }
 65
 66 /**
 67   - 重构代码,便于维护问题1:如果网速比较慢,会很卡
 68  解决方法:使用异步下载
 69
 70  问题2:图片没有Frame,所有cell初始化的时候,给imageView的frame是0。异步下载完之后不显示  解决办法:使用占位图(如果展位图比较大, 自定义cell可以解决)
 71
 72  问题3:如果图片下载速度不一致,同时用户快速滚动的时候,会因为Cell的重用导致图片混乱
 73  解决方法:MVC,使用Model(模型)保存下载的图像,再次刷新表格。
 74
 75  问题4:在用户快速滚动的时候,会重复添加下载任务到下载队列。
 76  解决方法:建立下载操作的缓冲池。首先检查缓冲池里是否有当前图片的下载操作。有的话就不创建下载操作。从而保证一张图片只添加一个下载操作。其实就是建立一个全局的字典属性。
 77
 78  问题5: 将图片保存到模型里的优缺点
 79  优点:不用重复下载,利用MVC刷新表格,不会造成数据混乱,加载速度比较快
 80  缺点:内存,所有下载好的图像都会记录在模型里。如果数据比较多(2000)个就会造成内存警告。
 81
 82  -***图像根模型耦合性太强。导致清理内存非常困难
 83  解决办法:模型跟图像分开。在控制器里做缓存。
 84  问题6:下载操作缓冲池会越来越大。需要及时清理。
 85
 86  */
 87 /**
 88  代码重构:1.如果代码太长。
 89  目的:
 90  - 写的时候,如果思路清楚,能够一次性写完,但是也要注意同构。
 91  - 时间长了,不好阅读
 92
 93
 94  重构方法:
 95  如果有一部分代码专门解决某一问题,就封装起来。
 96  1. 新建一个方法—> 剪切代码。
 97  2. 传参数。
 98  3. 在原来剪切代码的地方,调用抽取的方法。
 99  4. 注意,测试。
100  5. 注意if嵌套,在实际的开发,非常忌讳很深的嵌套。
101  */
102
103 -(void)viewDidLoad
104 {
105     NSLog(@"%@", [self cachePathWithUrl:@""]);
106 }
107
108 // cell里面的imageView子控件是懒加载
109 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
110 {
111     static NSString *ID = @"AppCell";
112     UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:ID];
113     // 给Cell设置数据
114     CZApp *app = self.appList[indexPath.row];
115     cell.textLabel.text = app.name;
116     cell.detailTextLabel.text = app.download;
117
118     // 判断模型里面是否有图像
119     if ([self.imageCache objectForKey:app.icon]) { // 内存有图片
120         NSLog(@" 图片已经下载......");
121         cell.imageView.image = self.imageCache[app.icon];
122     }else{
123         // 内存无图片
124         // 显示图片
125         // 如果沙盒里面有图片,直接从沙盒加载
126         UIImage *image = [UIImage imageWithContentsOfFile:[self cachePathWithUrl:app.icon]];
127         if (image) {   //  沙盒有图片
128             NSLog(@"直接从沙盒加载图片");
129             // 1. 设置图片缓存到内存,方便下次从内存直接加载
130             [self.imageCache setObject:image forKey:app.icon];
131
132             // 2. 显示图片到cell
133             cell.imageView.image = self.imageCache[app.icon];
134         }else{  // 沙盒没有图片
135
136             // 显示图片—占位图
137             cell.imageView.image = [UIImage imageNamed:@"user_default"];
138 //#warning mark-从这里开始剪切的代码
139
140             // 下载图片
141             [self downloadImage:indexPath];
142         }
143     }
144     return cell;
145 }
146
147 -(void)downloadImage:(NSIndexPath *)indexPath
148 {
149     CZApp *app = self.appList[indexPath.row];
150     /**
151      如果下载缓冲池里面有当前图片的下载操作,就不用创建下载操作,没有才创建
152      缓冲池字典中 key:存放当前图片的url,字符串类型。
153      Value:保存下载操作
154      */
155     if (self.operationCache[app.icon])
156     {
157         NSLog(@"正在玩命下载中......");
158         return;
159     }
160     // 缓冲池没有下载操作
161
162     // 异步下载图片
163     __weak typeof(self) weakSelf = self;
164     NSBlockOperation  *downLoadOp = [NSBlockOperation blockOperationWithBlock:^{
165         // 模拟延时
166         [NSThread sleepForTimeInterval:2];
167         NSLog(@"正在下载中......");
168
169         //  1. 下载图片(二进制数据)
170         NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]];
171         NSLog(@"%@", data);
172         UIImage *image = [UIImage imageWithData:data];
173
174         //  2. 将下载的数据保存到沙盒
175         // 字典的赋值不能为nil,赋值为nil会崩溃
176         if (image) {
177             // 先保存到图片缓存
178             [weakSelf.imageCache setObject:image forKey:app.icon];
179
180             // 将图片写入到沙盒
181             [data writeToFile:[self cachePathWithUrl:app.icon] atomically:YES];
182         }
183
184         // 3 将操作从缓冲池删除——将下载好的图片操作从缓冲池中移除
185         [weakSelf.operationCache removeObjectForKey:app.icon];
186
187         //  4. 在主线程更新UI
188         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
189             [weakSelf.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
190             /** reload 会重新调用cell的初始化方法, 会重新判断模型里面是否有图像
191              有的话就直接显示
192              */
193         }];
194     }];
195
196     // 将操作添加到队列
197     [weakSelf.opQueue addOperation:downLoadOp];
198     NSLog(@"操作的数量------------->%ld", self.opQueue.operationCount);
199
200     // 将操作添加到缓冲池中(使用图片的url作为key)
201     [weakSelf.operationCache setObject:downLoadOp forKey:app.icon];
202 }
203
204 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
205 {   // 点击后查看操作缓冲池内的操作详情
206     NSLog(@"%@", self.operationCache);
207 }
208
209 /**
210  在真实开发中,一定要注意这个方法
211  */
212 -(void)didReceiveMemoryWarning
213 {
214     [super didReceiveMemoryWarning];
215
216     // 需要在这里做一些内存清理的工作,如果不处理会被系统强制闪退
217     // 清理内存
218     [self.imageCache  removeAllObjects];
219
220     // 清理操作的缓存
221     [self.operationCache removeAllObjects];
222
223     // 取消下载队列内的任务
224     [self.opQueue cancelAllOperations];
225 }
226
227 /**
228  拼接一个文件在沙盒的全路径
229  */
230 -(NSString *)cachePathWithUrl:(NSString *)urlStr
231 {  // 将图片网址名作为作为最后一项
232     // 1. 获得缓存的路径
233     NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
234
235     // 2. 把路径根urlStr拼接起来
236     return [cachePath stringByAppendingPathComponent:urlStr.lastPathComponent];
237 }
238 -(void)dealloc
239 {
240     NSLog(@"销毁控制器-------------");
241 }
242 @end

有沙盒路径对我们比较重要,因为他能够让我们在断网且退出程序后,在进入程序任然能够使用。当然我们也必须限制沙盒中存入数据的个数,最好能让其更新。这样我们就无需担心没有网时只能看见很久以前的消息。

下一篇会说如何更新缓存。

 

转载于:https://www.cnblogs.com/YU411524/p/4929585.html

iOS篇之有沙盒缓存相关推荐

  1. IOS模拟登录之沙盒原理

    IOS模拟登录之沙盒原理 info.plist 文件

  2. iOS 照片存储到沙盒 和读取

    iOS 照片存储到沙盒 和读取 这里介绍简单的ios照片保存到沙盒,然后读取出来. 1. 照片保存到沙盒 UIImage *image=[UIImage imageNamed:@"20141 ...

  3. IOS数据存储 —— 1 沙盒(数据存储目录)

    沙盒结构 沙盒的文件系统⽬录,如下图所示(假设应用的名称叫Layer) 1.Documents 目录 您应该将所有的应用程序数据文件写入到这个目录下. 这个目录用于存储用户数据或其它应该定期备份的信息 ...

  4. iOS打开沙盒html,ios 开发中,沙盒目录解释

    在iPhone的沙箱模型有四个文件夹,分别是documents.tmp.app.library. 创建文件的时候会先创建文件的路径,方法如下: 1.Documents:这是文档目录.有关应用的所有数据 ...

  5. iOS开发 - 内购沙盒测试正常,因产品返回数为0被苹果审核多次拒绝 (In-app purchase products return 0)

    最近给app增加内购移除广告功能,刚开始还比较顺利,把网上找到的内购代码,简单修改加入到app内,基本能用,测试完成后,提交审核.第一次提交,有点问题被拒,根据具体问题进行改正后,再提交,审核就通过了 ...

  6. 再谈CVE-2017-7047 Triple_Fetch和iOS 10.3.2沙盒逃逸

    作者:蒸米 0x00 序 Ian Beer@google发布了CVE-2017-7047Triple_Fetch的exp和writeup[1],chenliang@keenlab也发表了关于Tripl ...

  7. IOS文件管理系统:沙盒、NSFileManager、NSFileHandle、NSCoding、NSKeyedArchiver解析

    什么是沙盒? 苹果为我们每个app都分配了一个固定的文件夹,我们在开发过程中可以向文件夹存入我们想要存储的数据,同时也能从这些文件夹取这些数据,但是我们不能取到其他app所存储的数据.简单说,沙盒就是 ...

  8. ios沙箱软件_iOS沙盒管理工具FHHSandBoxViewer

    KeyWord:沙盒文件递归遍历.Swift里的闭包多个weak修饰.iOS使用AirDrop 操作演示.gif 平时真机开发调试App的时候想查看沙盒具体内容一般做法是连接Xcode下载整个App的 ...

  9. ios 模拟器沙盒_举例详解iOS开发过程中的沙盒机制与文件

    iOS沙盒机制 iOS应用程序只能在为该改程序创建的文件系统中读取文件,不可以去其它地方访问,此区域被成为沙盒,所以所有的非代码文件都要保存在此,例如图像,图标,声音,映像,属性列表,文本文件等. 每 ...

最新文章

  1. springboot运行原理
  2. Vue安装live-server
  3. 遮掩java_Java×××:重载、重写、隐藏、遮蔽、遮掩(2)
  4. python字典的应用实验报告_Python字典应用的一个例子
  5. 2020-python小工能
  6. 软件测试学习指南(更新中)
  7. 安卓中圆角背景图被拉伸的解决方案——.9.png
  8. python bunch制作可导入数据_Python 之 Bunch Pattern
  9. 【python量化】用时间卷积神经网络(TCN)进行股价预测
  10. Anbox安卓apk应用安装及使用说明和常见问题
  11. R语言 非参数检验:Mann-Whitney检验和Wilcoxon检验
  12. django 解析上传xls文件
  13. 优恩-关于ESD管(ESD静电二极管)的产品特性
  14. prometheus+alertmanager 企业微信告警
  15. Go panic的学习
  16. 详解Unity中的导入3D模型
  17. s5pv210 i2c 时序
  18. 猿辅导2021校园招聘技术类笔试(一) 题解
  19. 简单的出入库管理软件一体化管理
  20. 给深度学习研究生的入门建议(未完待续ing)

热门文章

  1. 从linux使用sz命令下载大于4g的文件到windows
  2. linux系统 设置网卡ping通主机连上外网
  3. python rest api client_Python py-jama-rest-client包_程序模块 - PyPI - Python中文网
  4. 客户商品生命周期应用
  5. 为什么rstudio打开是空白的_既然大家都说装了win10,就不用鲁大师监测显卡温度,为什么呢?...
  6. Python 柱状图 横坐标 名字_Python爬虫实例(二)——爬取新馆疫情每日新增人数
  7. 事件对象以及事件委托(pink老师笔记)
  8. 【李宏毅机器学习】01:机器学习介绍 Introduction
  9. Mysql 联合索引入门
  10. hive判断是否包含