zoukankan      html  css  js  c++  java
  • ios开发缓存处理类NSCash类的了解与使用

    一:NSCash的基本了解

    #import "ViewController.h"
    
    @interface ViewController ()<NSCacheDelegate>
    /** 注释 */
    @property (nonatomic, strong) NSCache *cache;
    @end
    
    @implementation ViewController
    
    -(NSCache *)cache
    {
        if (_cache == nil) {
            _cache = [[NSCache alloc]init];
            _cache.totalCostLimit = 5;//总成本数是5 ,如果发现存的数据超过中成本那么会自动回收之前的对象(假设有10个成本,totalCostLimit为5,超过5个之后,在最前面创建的成本就会被回收)
            _cache.delegate = self;
        }
        return _cache;
    }
    
    //存数据:
    /**
     * 1:NSCache的Key只是对对象进行Strong引用,不是拷贝(和可变字典的区别),而字典是对key进行的拷贝
       2:[self.cache setObject:data forKey:@(i) cost:1];const代表成本,若是data的值写在外界,每次得到的都是同一个对象,则总的成本为1,若是在里面每次获得都是新的对象,则所获得总成本为10。也就是10次执行的对象若都是同一个,则成本计算只会为1,若十次得到的都是不同的对象,则总成本为10
     *
     */
    - (IBAction)addBtnClick:(id)sender
    {
        //NSCache的Key只是对对象进行Strong引用,不是拷贝(和可变字典的区别)
        for (NSInteger i = 0; i<10; i++) {
           NSData *data = [NSData dataWithContentsOfFile:@"/Users/xiaomage/Desktop/Snip20160221_38.png"];
            
            //cost:成本,
            [self.cache setObject:data forKey:@(i) cost:1];
            NSLog(@"存数据%zd",i);
        }
    }
    
    //取数据
    
    /**
     * 1:当去取数据的时候或是接受外界传递的参数的时候,严禁一些要进行判断,判断该值是否存在
     *
     */
    - (IBAction)checkBtnClick:(id)sender
    {
        NSLog(@"+++++++++++++++");
        for (NSInteger i = 0; i<10; i++) {
            NSData *data = [self.cache objectForKey:@(i)];
            if (data) {
                NSLog(@"取出数据%zd",i);
            }
        }
    }
    
    //删除数据
    - (IBAction)removeBtnClick:(id)sender
    {
        [self.cache removeAllObjects];
    }
    
    #pragma mark ----------------------
    #pragma mark NSCacheDelegate
    //即将回收对象的时候调用该方法
    -(void)cache:(NSCache *)cache willEvictObject:(id)obj
    {
        NSLog(@"回收%zd",[obj length]);
    }
    @end

    1.SDWebImage相关知识点补充

      01.SDWebImage接收到内存警告的时候如何处理?采用监听系统警告通知的方式处理,接收到警告后清空缓存

      02.SDWebImage队列最大并发数为6

      03.SDWebImage内部设置下载图片超时时间为15m

      04.SDWebImage图片下载操作使用了NSURLConnection类发送网络请求实现

      05.SDWebImage内部使用NSCache类来进行缓存处理

      06.SDWebImage内部如何判断图片类型?判断该图片二进制数据的第一个字节

      07.SDWebImage做沙盒缓存时图片的命名机制是拿到图片的URL后直接对URL进行MD5加密

    2.NSCache知识点补充

     01.NSCache是专门用来进行缓存处理的,

     02.NSCache简单介绍:

        2-1 NSCache是苹果官方提供的缓存类,具体使用和NSDictionary类似,在AFN和SDWebImage框架中被使用来管理缓存

        2-2 苹果官方解释NSCache在系统内存很低时,会自动释放对象(但模拟器演示不会释放)

            建议:接收到内存警告时主动调用removeAllObject方法释放对象

        2-3 NSCache是线程安全的,在多线程操作中,不需要对NSCache加锁

        2-4 NSCache的Key只是对对象进行Strong引用,不是拷贝

     03 属性介绍:

        name:名称

        delegete:设置代理

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

        countLimit:能够缓存的对象的最大数量。默认值为0,表示没有限制

        evictsObjectsWithDiscardedContent:标识缓存是否回收废弃的内容

     04 方法介绍

    - (void)setObject:(ObjectType)obj forKey:(KeyType)key;//在缓存中设置指定键名对应的值,0成本

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

    - (void)removeObjectForKey:(KeyType)key;//删除缓存中指定键名的对象

    - (void)removeAllObjects;//删除缓存中所有的对象

     二:NSCash的使用:

    #import "ViewController.h"
    #import "XMGAPP.h"
    
    @interface ViewController ()
    /** tableView的数据源 */
    @property (nonatomic, strong) NSArray *apps;
    /** 内存缓存 */
    @property (nonatomic, strong) NSCache *images;
    /** 队列 */
    @property (nonatomic, strong) NSOperationQueue *queue;
    /** 操作缓存 */
    @property (nonatomic, strong) NSMutableDictionary *operations;
    @end
    
    @implementation ViewController
    
    #pragma mark ----------------------
    #pragma mark lazy loading
    -(NSOperationQueue *)queue
    {
        if (_queue == nil) {
            _queue = [[NSOperationQueue alloc]init];
            //设置最大并发数
            _queue.maxConcurrentOperationCount = 5;
        }
        return _queue;
    }
    -(NSCache *)images
    {
        if (_images == nil) {
            _images = [[NSCache alloc]init];
    
            //设置最多可以缓存多少个数据
            //_images.countLimit = 4;
        }
        return _images;
    }
    -(NSArray *)apps
    {
        if (_apps == nil) {
            
            //字典数组
            NSArray *arrayM = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil]];
            
            //字典数组---->模型数组
            NSMutableArray *arrM = [NSMutableArray array];
            for (NSDictionary *dict in arrayM) {
                [arrM addObject:[XMGAPP appWithDict:dict]];
            }
            _apps = arrM;
        }
        return _apps;
    }
    
    -(NSMutableDictionary *)operations
    {
        if (_operations == nil) {
            _operations = [NSMutableDictionary dictionary];
        }
        return _operations;
    }
    
    #pragma mark ----------------------
    #pragma mark UITableViewDatasource
    -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return 1;
    }
    
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return self.apps.count;
    }
    
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *ID = @"app";
        
        //1.创建cell
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
        
        //2.设置cell的数据
        //2.1 拿到该行cell对应的数据
        XMGAPP *appM = self.apps[indexPath.row];
        
        //2.2 设置标题
        cell.textLabel.text = appM.name;
        
        //2.3 设置子标题
        cell.detailTextLabel.text = appM.download;
        
        //2.4 设置图标
        
        //先去查看内存缓存中该图片时候已经存在,如果存在那么久直接拿来用,否则去检查磁盘缓存
        //如果有磁盘缓存,那么保存一份到内存,设置图片,否则就直接下载
        //1)没有下载过
        //2)重新打开程序
        
        UIImage *image = [self.images objectForKey:appM.icon];
        if (image) {
            cell.imageView.image = image;
            NSLog(@"%zd处的图片使用了内存缓存中的图片",indexPath.row) ;
        }else
        {
            //保存图片到沙盒缓存
            NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
            //获得图片的名称,不能包含/
            NSString *fileName = [appM.icon lastPathComponent];
            //拼接图片的全路径
            NSString *fullPath = [caches stringByAppendingPathComponent:fileName];
            
            
            //检查磁盘缓存
            NSData *imageData = [NSData dataWithContentsOfFile:fullPath];
            //废除
            imageData = nil;
            
            if (imageData) {
                UIImage *image = [UIImage imageWithData:imageData];
                cell.imageView.image = image;
                
                NSLog(@"%zd处的图片使用了磁盘缓存中的图片",indexPath.row) ;
                //把图片保存到内存缓存
                [self.images setObject:image forKey:appM.icon];
                
    //            NSLog(@"%@",fullPath);
            }else
            {
                //检查该图片时候正在下载,如果是那么久什么都捕捉,否则再添加下载任务
                NSBlockOperation *download = [self.operations objectForKey:appM.icon];
                if (download) {
                    
                }else
                {
                    
                    //先清空cell原来的图片
                    cell.imageView.image = [UIImage imageNamed:@"Snip20160221_306"];
                    
                    download = [NSBlockOperation blockOperationWithBlock:^{
                        NSURL *url = [NSURL URLWithString:appM.icon];
                        NSData *imageData = [NSData dataWithContentsOfURL:url];
                        UIImage *image = [UIImage imageWithData:imageData];
                        
                         NSLog(@"%zd--下载---",indexPath.row);
                        
                        //容错处理
                        if (image == nil) {
                            [self.operations removeObjectForKey:appM.icon];
                            return ;
                        }
                        //演示网速慢的情况
                        //[NSThread sleepForTimeInterval:3.0];
                        
                        //把图片保存到内存缓存
                        [self.images setObject:image forKey:appM.icon];
                        
                        //NSLog(@"Download---%@",[NSThread currentThread]);
                        //线程间通信
                        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                            
                            //cell.imageView.image = image;
                            //刷新一行
                            [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
                            //NSLog(@"UI---%@",[NSThread currentThread]);
                        }];
                        
                        
                        //写数据到沙盒
                        [imageData writeToFile:fullPath atomically:YES];
                       
                        //移除图片的下载操作
                        [self.operations removeObjectForKey:appM.icon];
                        
                    }];
                    
                    //添加操作到操作缓存中
                    [self.operations setObject:download forKey:appM.icon];
                    
                    //添加操作到队列中
                    [self.queue addOperation:download];
                }
                
            }
        }
        
        //3.返回cell
        return cell;
    }
    
    #pragma mark ----------------------
    #pragma mark UITableViewDelegate
    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        
        NSArray *arrayM = self.apps;
        //检查缓存数据
        for (NSInteger i = 0; i < arrayM.count; i++) {
            XMGAPP *appM = arrayM[i];
            
            UIImage *image = [self.images objectForKey:appM.icon];
            if (image) {
                NSLog(@"存在图片缓存%zd",i);
            }
        }
    }
    
    -(void)didReceiveMemoryWarning
    {
        [self.images removeAllObjects];
        
        //取消队列中所有的操作
        [self.queue cancelAllOperations];
    }
    
    //1.UI很不流畅 --- > 开子线程下载图片
    //2.图片重复下载 ---> 先把之前已经下载的图片保存起来(字典)
    //内存缓存--->磁盘缓存
    
    //3.图片不会刷新--->刷新某行
    //4.图片重复下载(图片下载需要时间,当图片还未完全下载之前,又要重新显示该图片)
    //5.数据错乱 ---设置占位图片
    
    /*
     Documents:会备份,不允许
     Libray
        Preferences:偏好设置 保存账号
        caches:缓存文件
     tmp:临时路径(随时会被删除)
     */
    
    @end
  • 相关阅读:
    每日日报2020.12.1
    每日日报2020.11.30
    981. Time Based Key-Value Store
    1146. Snapshot Array
    565. Array Nesting
    79. Word Search
    43. Multiply Strings
    Largest value of the expression
    1014. Best Sightseeing Pair
    562. Longest Line of Consecutive One in Matrix
  • 原文地址:https://www.cnblogs.com/cqb-learner/p/5857048.html
Copyright © 2011-2022 走看看