NSCache

NSCache:专门做缓存的类

NSCache简介:NSCache是苹果官方提供的缓存类,用法与NSMutableDictionary的用法很相似,在AFNetworking和SDWebImage中,使用它来管理缓存。

NSCache在系统内存很低时,会自动释放一些对象(出自苹果官方文档,不过在模拟器中模拟内存警告时,不会做缓存的清理动作) 为了确保接收到内存警告时能够真正释放内存,最好调用一下removeAllObjects方法。

NScache是线程安全的,在多线程操作中,不需要对Cache加锁。

NScache的key只是做强引用,不需要实现NScopying协议。

NSCache的属性:

delegate代理属性

totalCostLimit :缓存空间的最大成本,超出上限会自动回收对象。默认值是0没有限制。

countLimit:能够缓存对象的最大数量,默认值也是0(默认没有限制)。

(当超出缓存最大成本或数量时,NSCache会把前面的数据即最开始存的给清除掉)

evictsObjectsWithDiscardedContent:标示是否回收废弃的内容,默认值是YES(自动回收)。

NSCache的方法:

-objectForKey:返回与键值关联的对象。

-setObject: forKey: 在缓存中设置指定键名对应的值。与可变字典不同的是,缓存对象不会对键名做copy操作 0成本

-setObject: forKey: cost: 在缓存中设置指定键名对应的值,并且指定该键值对的成本。成本cost用于计算记录在缓冲中所有对象的总成本。当出现内存警告,或者超出缓存的成本上限时,缓存会开启一个回收过程,删除部分元素。

-removeObjectForKey:删除缓存中指定键名的对象。

-removeAllObjects:删除缓存中的所有对象。

委托方法:

-cache: willEvictObject: 缓存将要删除对象时调用,不能在此方法中修改缓存。仅仅用于后台的打印,以便于程序员的测试。

实例:

  1. //
  2. //  CZApp.h
  3. //  NSoperation之网络图片下载
  4. //
  5. //  Created by apple on 15/10/23.
  6. //  Copyright (c) 2015年 LiuXun. All rights reserved.
  7. //
  8. #import <UIKit/UIKit.h>
  9. @interface CZApp : NSObject
  10. @property(nonatomic, copy) NSString *name;
  11. @property (nonatomic, copy) NSString *icon;
  12. @property (nonatomic, strong) NSString *download;
  13. /**
  14. 保存网络下载的图像
  15. */
  16. // @property(nonatomic, strong) UIImage *image;
  17. +(instancetype) appWithDict:(NSDictionary *) dict;
  18. @end

CZApp.m

[objc] view plain copy

  1. //
  2. //  CZApp.m
  3. //  NSoperation之网络图片下载
  4. //
  5. //  Created by apple on 15/10/23.
  6. //  Copyright (c) 2015年 LiuXun. All rights reserved.
  7. //
  8. #import "CZApp.h"
  9. @implementation CZApp
  10. +(instancetype) appWithDict:(NSDictionary *) dict
  11. {
  12. CZApp *app = [[self alloc] init];
  13. [app setValuesForKeysWithDictionary:dict];
  14. return app;
  15. }
  16. @end

viewController.m

[objc] view plain copy

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

NSCache的相关文章

多线程与网络之SDWebImage和NSCache

*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } a { color: #4183C4; } a.absent { color: #cc0000; } a.anchor { display: block; padding-left: 30px; margin-left: -30px; cursor: pointer; position: absolute

NSCache使用常见错误

NSCache用来存储缓存数据的时候.和NSDictionary功能类似, 可是NSCache有一个特别的问题: 一旦接收到内存警告之后,假设使用[NSCache removeAllObjects]处理就不能把图片存放到内存中, 之后全部的图片都是从沙盒中取的不能再次存放到内存中,由于框架的内存警告做了[NScache removeAllObjects]操作[NSCache removeAllObjects]操作之后不能再往NSCache中设置数据

NSCache 新手求带飞

NSCache是系统提供的一种类似于集合(NSMutableDictionary)的缓存, NSCache具有自动删除的功能,以减少系统占用的内存. 下面是简单的点击事件使用cache: - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { //系统用来缓存的类 NSCache * cache = [[NSCache alloc] init]; //totalCostLimit 设置缓存大小

step 3 NSCache

NSCache 介绍 NSCache 是苹果提供的一个专门用来做缓存的类 使用和 NSMutableDictionary 非常相似 是线程安全的 当内存不足的时候,会自动清理缓存 程序开始时,可以指定缓存的数量 & 成本 方法 1  取值 ?                     - (id)objectForKey:(id)key; 2  设置对象,0成本 ?                     - (void)setObject:(id)obj forKey:(id)key; 3  设

NSCache使用

苹果官方的解释 An NSCache object is a mutable collection that stores key-value pairs, similar to an NSDictionary object. The NSCache class provides a programmatic interface to adding and removing objects and setting eviction policies based on the total cost

iOS7: 漫谈基础集合类(NSArray,NSSet,NSOrderedSet,NSDictionary,NSMapTable,NSHashTable, NSPointerArray, NSIndexSet,NSCache, NSFastEnumeration)

基础集合类是每一个Mac/iOS应用的基本组成部分.在本文中,我们将对”老类”(NSArray, NSSet)和”新类”(NSMapTable, NSHashTable, NSPointerArray)进行一个深入的研究,探索每一个的效率细节,并讨论其使用场景. 提示:本文包含一些参照结果,但它们并不意味着绝对精确,也没有进行多个.复杂的测试.这些结果的目的是给出一个快速和主要的运行时统计.所有的测试基于iPhone 5s,使用Xcode 5.1b1和iOS 7.1b1,64位的程序.编译选项设

iOS开发之缓存框架、内存缓存、磁盘缓存、NSCache、TMMemoryCache、PINMemoryCache、YYMemoryCache、TMDiskCache、PINDiskCache

1.在项目中我们难免会用到一些缓存方式来保存服务器传过来的数据,以减少服务器的压力. 缓存的方式分为两种分别为内存缓存和磁盘缓存,内存缓存速度快容量小,磁盘缓存容量大速度慢可持久化.常见的内存缓存有NSCache.TMMemoryCache.PINMemoryCache.YYMemoryCache.常见的磁盘缓存有TMDiskCache.PINDiskCache.YYCache. 1.本文章着重讲下YYCache. 这是为什么呢,因为他比其他的缓存框架更加高效,使用方便. YYCache: 去掉

NSCache的简单使用

简介 1)NSCache 是苹果官方提供的缓存类,用法与 NSMutableDictionary 的用法很相似,在 AFNetworking 和 SDWebImage 中,使用它来管理缓存. 2)NSCache 在系统内存很低时,会自动释放一些对象(备注:在模拟器中内存警告时,缓存不会做清理动作).开发中为了确保收到内存警告时真正释放内存,最好调用 - (void)removeAllObjects; 方法. 3)NSCache 是线程安全的,在多线程操作中,不需要对 NSCache 加锁. 4)

NSCache类的简单介绍

最近看SDWebImage,里面的内存缓存用到了NSCache这个类,由于以前没有使用过,特此记录学习一下. NSCache NSCache是苹果官方提供的缓存类,用法和NSMutableDictonary非常类似. NSCache是一个类似于集合的容器,即缓存.它存储key-value,这一点非常类似字典.开发者一般用NSCache来缓存临时存储短时间但是使用成本高的对象.重用这些对象可以优化性能,因为它们的值不在被重新计算.另外一方面,这些对象对于程序来说是不要紧的,在内存紧张的时候会被丢弃