内存指的就是主板上的存储部件,是CPU直接与之沟通,并用其存储数据的部件,存放当前正在使用的(即执行中)的数据和程序,它的物理实质就是一组或多组具备数据输入输出和数据存储功能的集成电路,内存只用于暂时存放程序和数据,一旦关闭电源或发生断电,其中的程序和数据就会丢失。
 #import "ViewController.h"
#import "CZApp.h"
@interface ViewController ()
// plist文件数据的容器
@property (nonatomic, strong) NSArray *appList; // 管理下载的全局队列
@property (nonatomic, strong) NSOperationQueue *opQueue; /**所有下载的缓冲池*/
@property (nonatomic, strong) NSMutableDictionary *operationCache; /**保存所有图像的缓存*/
@property (nonatomic, strong) NSMutableDictionary *imageCache;
@end @implementation ViewController // 懒加载
-(NSArray *)appList
{
if (_appList == nil) {
NSArray *dicArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil]];
// 字典转模型
NSMutableArray *arryM = [NSMutableArray array];
for(NSDictionary *dict in dicArray){
CZApp *app = [CZApp appWithDict:dict];
[arryM addObject:app];
}
_appList = arryM;
}
return _appList;
} -(NSOperationQueue *)opQueue
{
if (_opQueue == nil) {
_opQueue = [[NSOperationQueue alloc] init];
}
return _opQueue;
} -(NSMutableDictionary *)operationCache
{
if (_operationCache == nil) {
_operationCache = [[NSMutableDictionary alloc] init];
}
return _operationCache;
} -(NSMutableDictionary *)imageCache
{
if (_imageCache == nil) {
_imageCache = [[NSMutableDictionary alloc] init];
}
return _imageCache;
} #pragma mark - 实现数据源方法
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.appList.count;
} /**
- 重构代码,便于维护问题1:如果网速比较慢,会很卡
解决方法:使用异步下载 问题2:图片没有Frame,所有cell初始化的时候,给imageView的frame是0。异步下载完之后不显示 解决办法:使用占位图(如果展位图比较大, 自定义cell可以解决) 问题3:如果图片下载速度不一致,同时用户快速滚动的时候,会因为Cell的重用导致图片混乱
解决方法:MVC,使用Model(模型)保存下载的图像,再次刷新表格。 问题4:在用户快速滚动的时候,会重复添加下载任务到下载队列。
解决方法:建立下载操作的缓冲池。首先检查缓冲池里是否有当前图片的下载操作。有的话就不创建下载操作。从而保证一张图片只添加一个下载操作。其实就是建立一个全局的字典属性。 问题5: 将图片保存到模型里的优缺点
优点:不用重复下载,利用MVC刷新表格,不会造成数据混乱,加载速度比较快
缺点:内存,所有下载好的图像都会记录在模型里。如果数据比较多(2000)个就会造成内存警告。 -***图像根模型耦合性太强。导致清理内存非常困难
解决办法:模型跟图像分开。在控制器里做缓存。
问题6:下载操作缓冲池会越来越大。需要及时清理。 */
/**
代码重构:1.如果代码太长。
目的:
- 写的时候,如果思路清楚,能够一次性写完,但是也要注意同构。
- 时间长了,不好阅读 重构方法:
如果有一部分代码专门解决某一问题,就封装起来。
1. 新建一个方法—> 剪切代码。
2. 传参数。
3. 在原来剪切代码的地方,调用抽取的方法。
4. 注意,测试。
5. 注意if嵌套,在实际的开发,非常忌讳很深的嵌套。
*/ -(void)viewDidLoad
{
NSLog(@"%@", [self cachePathWithUrl:@""]);
} // cell里面的imageView子控件是懒加载
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID = @"AppCell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 给Cell设置数据
CZApp *app = self.appList[indexPath.row];
cell.textLabel.text = app.name;
cell.detailTextLabel.text = app.download; // 判断模型里面是否有图像
if ([self.imageCache objectForKey:app.icon]) { // 内存有图片
NSLog(@" 图片已经下载......");
cell.imageView.image = self.imageCache[app.icon];
}else{
// 内存无图片
// 显示图片
// 如果沙盒里面有图片,直接从沙盒加载
UIImage *image = [UIImage imageWithContentsOfFile:[self cachePathWithUrl:app.icon]];
if (image) { // 沙盒有图片
NSLog(@"直接从沙盒加载图片");
// 1. 设置图片缓存到内存,方便下次从内存直接加载
[self.imageCache setObject:image forKey:app.icon]; // 2. 显示图片到cell
cell.imageView.image = self.imageCache[app.icon];
}else{ // 沙盒没有图片 // 显示图片—占位图
cell.imageView.image = [UIImage imageNamed:@"user_default"];
//#warning mark-从这里开始剪切的代码 // 下载图片
[self downloadImage:indexPath];
}
}
return cell;
} -(void)downloadImage:(NSIndexPath *)indexPath
{
CZApp *app = self.appList[indexPath.row];
/**
如果下载缓冲池里面有当前图片的下载操作,就不用创建下载操作,没有才创建
缓冲池字典中 key:存放当前图片的url,字符串类型。
Value:保存下载操作
*/
if (self.operationCache[app.icon])
{
NSLog(@"正在玩命下载中......");
return;
}
// 缓冲池没有下载操作 // 异步下载图片
__weak typeof(self) weakSelf = self;
NSBlockOperation *downLoadOp = [NSBlockOperation blockOperationWithBlock:^{
// 模拟延时
[NSThread sleepForTimeInterval:];
NSLog(@"正在下载中......"); // 1. 下载图片(二进制数据)
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]];
NSLog(@"%@", data);
UIImage *image = [UIImage imageWithData:data]; // 2. 将下载的数据保存到沙盒
// 字典的赋值不能为nil,赋值为nil会崩溃
if (image) {
// 先保存到图片缓存
[weakSelf.imageCache setObject:image forKey:app.icon]; // 将图片写入到沙盒
[data writeToFile:[self cachePathWithUrl:app.icon] atomically:YES];
} // 3 将操作从缓冲池删除——将下载好的图片操作从缓冲池中移除
[weakSelf.operationCache removeObjectForKey:app.icon]; // 4. 在主线程更新UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[weakSelf.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
/** reload 会重新调用cell的初始化方法, 会重新判断模型里面是否有图像
有的话就直接显示
*/
}];
}]; // 将操作添加到队列
[weakSelf.opQueue addOperation:downLoadOp];
NSLog(@"操作的数量------------->%ld", self.opQueue.operationCount); // 将操作添加到缓冲池中(使用图片的url作为key)
[weakSelf.operationCache setObject:downLoadOp forKey:app.icon];
} -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{ // 点击后查看操作缓冲池内的操作详情
NSLog(@"%@", self.operationCache);
} /**
在真实开发中,一定要注意这个方法
*/
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning]; // 需要在这里做一些内存清理的工作,如果不处理会被系统强制闪退
// 清理内存
[self.imageCache removeAllObjects]; // 清理操作的缓存
[self.operationCache removeAllObjects]; // 取消下载队列内的任务
[self.opQueue cancelAllOperations];
} /**
拼接一个文件在沙盒的全路径
*/
-(NSString *)cachePathWithUrl:(NSString *)urlStr
{ // 将图片网址名作为作为最后一项
// 1. 获得缓存的路径
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; // 2. 把路径根urlStr拼接起来
return [cachePath stringByAppendingPathComponent:urlStr.lastPathComponent];
}
-(void)dealloc
{
NSLog(@"销毁控制器-------------");
}
@end

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

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

 

iOS篇之有沙盒缓存的更多相关文章

  1. iOS开发之获取沙盒路径

    iOS开发之沙盒机制(SandBox)具体解说了沙盒的一些机制.在开发中,我们须要对沙盒进行操作.所以我们须要获取到沙盒路径. 沙盒里的目录包含Documents.Library.tmp.这三个目录的 ...

  2. iOS开发——多线程篇——快速生成沙盒目录的路径,多图片下载的原理、SDWebImage框架的简单介绍

    一.快速生成沙盒目录的路径 沙盒目录的各个文件夹功能 - Documents - 需要保存由"应用程序本身"产生的文件或者数据,例如:游戏进度.涂鸦软件的绘图 - 目录中的文件会被 ...

  3. ionic项目打包好Xcode工程,模拟器运行各种沙盒缓存目录

    用ionic开发好的app,build好iOS端可用的Xcode工程,然后用模拟器跑起来.研究一下js写的代码做本地持久化时,不同类型的文件都放在那里了. cordova-plugin-sqliteS ...

  4. iOS 文件操作:沙盒(SandBox)、文件操作(FileManager)、程序包(NSBundle)

    版权声明:本文为博主原创文章,转载请声明出处:http://blog.csdn.net/jinnchang 1.沙盒机制介绍 iOS 中的沙盒机制(SandBox)是一种安全体系.每个 iOS 应用程 ...

  5. 【Swift】沙盒缓存

    本地sandbox缓存目录     沙盒の 主目录: po NSHomeDirectory()   /Users/SpongeBob/Library/Developer/CoreSimulator/D ...

  6. iOS开发之应用沙盒

    1.应用沙盒概述 每个iOS应用都有自己的应用沙盒(应用沙盒就是文件系统目录),与其他文件系统隔离.应用必须待在自己的沙盒里,其他应用不能访问该沙盒. 应用沙盒的文件系统目录,如下图所示(假设应用的名 ...

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

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

  8. APNS IOS 消息推送沙盒模式和发布模式

    在做.NET向IOS设备的App进行消息推送时候,采用的是PushSharp开源类库进行消息的推送,而在开发过程中,采用的是测试版本的app,使用的是测试的p12证书采用的是ApnsConfigura ...

  9. Swift iOS 文件操作:沙盒(SandBox)、程序包(NSBundle)

    1.沙盒机制介绍 iOS 中的沙盒机制(SandBox)是一种安全体系.每个 iOS 应用程序都有一个单独的文件系统(存储空间),而且只能在对应的文件系统中进行操作,此区域被称为沙盒.所有的非代码文件 ...

随机推荐

  1. Python基础 基本运算符

    什么是操作符 形如 1+1 = 2 这样的 1 就是操作数 + 就是操作符 python语言支持的操作符: 算数运算符 比较运算符(关系) 赋值运算符 逻辑运算符 位运算符 会员操作符 标志操作符 算 ...

  2. NSString 截取字符串

    NSString字符串常用方法2010-09-06 14:18/******************************************************************** ...

  3. HDU 1160 FatMouse's Speed (sort + dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1160 给你一些老鼠的体重和速度,问你最多需要几只可以证明体重越重速度越慢,并输出任意一组答案. 结构体 ...

  4. C#委托及事件处理机制浅析

    事件可以理解为某个对象所发出的消息,以通知特定动作(行为)的发生或状态的改变.行为的发生可能是来自用户交互,如鼠标点击:也可能源自其它的程序逻辑.在这里,触发事件的对象被称为事件(消息)发出者(sen ...

  5. C# 与 C++ 数据类型对照

    C++            C#=====================================WORD            ushortDWORD            uintUCH ...

  6. c++中的signal机制

    简介 signal是为了解决类之间通信的问题而出现的,更深入的原因是面向对象讲究封装,但是封装必然导致类之间沟通困难,但是使用接口的方式又太重量级--需要写很多代码,而且会导致接口爆炸 比如你需要把一 ...

  7. winrar激活

    (从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期2014-02-11) 新建记事本文件(txt文件),然后将文件另存为以 rarreg.key 为文件名的文件(当然由于设置的不同,可能 ...

  8. sqlite 对表的操作

    查询某个表的创建语法 select sql from sqlite_master where tbl_name="your_table_name" and type='table' ...

  9. myeclipse、eclipse中项目复制后(可能无法访问)注意事项 .

    .myEclipse 复制后修改名称,访问不到项目 这是因为,你只是改了项目的名称,而没有改 下面是解决方法: 方法 1.右击你的项目,选择“properties”,在“type filter tex ...

  10. grunt入门之grunt watch的使用

    watch几乎是grunt必不可少的应用,一旦配置好watch,保存文件后将立即执行命令 安装方式如下: npm install grunt-contrib-watch --save-dev 安装好以 ...