缓存与删除

  • 每一个APP的设置里,我想都会有一条是和存储相关的。在现在的APP设计中,图片、动画、声音等浏览之后并不会立即删除,因为这第一是浪费流量(当然wifi就不存在了),第二是浪费时间,尤其是网速慢得用户,用户体验就相当不好了,而APP缓存的内容可以根据用户需求进行删除。
  • 沙盒机制:iPhone是没有内存卡这个东西的,存储的地方叫做沙盒,关于沙盒的介绍http://blog.csdn.net/zhenzhenzhao12/article/details/8162793,这个网址中介绍的非常清楚,我在之前结合一些代码也有做比较详细的分析。就直接拿过来用,不另外总结了。

归档

  • 什么叫归档:

    • 持久化的意思,用某种格式保存一个对象叫做归档。
  • 应用沙盒:每个应用都有自己的文件夹,互不干扰,保障安全性。

    • 资源包:图片资源,plist资源。
    • Docunments
    • Library
      • Caches
      • Preferences
    • tmp
  • 沙盒位置:前往->资源库->Developer->CoreSimulator->Devices

    • 可以在自己的应用中打印其路径:NSLog(@"沙盒路径:%@",NSHomeDirectory());
  • Documents
    • 需要保存由应用程序本身产生的需要持久化文件或者数据,iTunes同步设备时会备份该目录。例如:游戏进度、涂鸦软件的绘图。
    • 目录中的文件会被自动保存在iCloud、iTunes.
    • 注意:不要保存从网路上下载的文件,否则会无法上架。
  • 01Plist文件存储
    • plist存储
    • 将plist文件存入沙盒中,再从沙盒中读取。保存在Documents中。
    • 如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型。就可以用writeToFile直接写到属性列表文件中。
    // 地址拼接
    NSString *docData = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
    
    // 创建数据
    NSArray *array = @[@10,@"name",@"picture"];
    // 获取最终地址
    NSString *data = [docData stringByAppendingPathComponent:@"data.plist"];
   
    // 存
    [array writeToFile:data atomically:YES];
    // 地址拼接
    NSString *docData = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
    // 获取最终地址
    NSString *data = [docData stringByAppendingPathComponent:@"data.plist"];
    
    NSArray *array = [NSArray arrayWithContentsOfFile:data];
  • 02 对象的存储 archive(归档)
    • 什么是归档
    • 这种方式可以对字符串、数字等进行归档,当然也可以对NSArray与NSDictionary进行归档。可以归档多个对象。可以对自定义对象进行归档。
  • (1)单一简单操作
// 归档
NSString *homeDictionary = NSHomeDirectory();//获取根目录 
NSString *homePath  = [homeDictionary stringByAppendingPathComponent:@"atany.archiver"];//添加储存的文件名  
BOOL flag = [NSKeyedArchiver archiveRootObject:@”归档” toFile:homePath];//归档一个字符串
// 接档
[NSKeyedUnarchiver unarchiveObjectWithFile:homePath]  
  • (2)多对象归档:使用encodeXXX方法进行归档,最后通过writeToFile方法写入文件。
//准备数据  
CGPoint point = CGPointMake(1.0, 2.0);  
NSString *info = @"坐标原点";  
NSInteger value = 10;  
NSString *multiHomePath = [NSHomeDirectory() stringByAppendingPathComponent:@"multi.archiver"];  
NSMutableData *data = [[NSMutableData alloc]init];  
NSKeyedArchiver *archvier = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];  
  
//对多个对象进行归档  
[archvier encodeCGPoint:point forKey:@"kPoint"];  
[archvier encodeObject:info forKey:@"kInfo"];  
[archvier encodeInteger:value forKey:@"kValue"];  
[archvier finishEncoding];  
[data writeToFile:multiHomePath atomically:YES];  
  • 接档:从路径中获得数据构造NSKeyedUnarchiver实例,使用decodeXXXForKey方法获得文件中的对象。
NSMutableData *dataR = [[NSMutableData alloc]initWithContentsOfFile:multiHomePath];  
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:dateR];  
CGPoint pointR = [unarchiver decodeCGPointForKey:@"kPoint"];  
NSString *infoR = [unarchiver decodeObjectForKey:@"kInfo"];  
NSInteger valueR = [unarchiver decodeIntegerForKey:@"kValue"];  
[unarchiver finishDecoding];  
NSLog(@"%f,%f,%@,%d",pointR.x,pointR.y,infoR,valueR);  
  • (3)自定义对象进行归档
    • 自定义对象实现了两个委托方法1)encodeWithCoder: 2)initWithCoder:
    • 1)encodeWithCoder
Encodes the receiverusing a given archiver
// 通过一个给定的archiver把消息接收者进行编码。当接收到encodeObject消息的时候,类终端encodeWithCoder方法被调用。
  • 2)initWithCoder
Returns an objectinitialized from data in a given unarchiver. (required)
// 从一个给定unarchiver的数据中返回一个初始化对象。
  • Library
  • 01 Caches
    • 保存临时文件,后续需要使用,例如:缓存图片,离线数据(地图数据)。
    • 系统不会清理cache目录中的文件。
    • 要求程序开发时,必须提供Caches目录的清理解决方案。
  • 02 Preferences
    • 保存应用的所有偏好设置,使用NSUserDefault直接读写。(账号密码)。iTunes会同步设备时会备份该目录。
    • 如果要想数据及时写入磁盘,还需要调用一个同步方法。
    • 偏好设置一般是利用键值对保存,本质上也是plist文件,但是不用去找寻地址,有对应的文件夹,对应的方法查询地址,保存。
// 存储
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"jack" forKey:@"name"];
[defaults setBool:YES forKey:@"isOk"];
// 同步
[defaults synchronize];
// 读取
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *name = [defaults objectForKey:@"name"];
NSLog(@"%@",name);
  • tmp
    • 保存临时文件,后续不需要使用一般缓存比较大的,不重要的数据。
    • tmp目录中的文件,系统会自动清理。
    • 重新启动手机,tem目录会被清空。
    • 系统磁盘空间不足时,系统会自动清理。
  • SQLite3(数据库存储)

    • 存储效率最高。(封装了很多查询、删除的算法)
    • 是关系型数据库。需要使用数据库语句。
  • 清除缓存


    缓存与删除_第1张图片
    03.gif
  • 界面处理。

    • 01分析:这个界面的处理是非常简单的,因为我这里只搭建了一个tableViewCell。可以明显的感觉到tableViewCell和一般的设置界面的cell不一样,所以这个cell可以单独认证一个ID,其他的cell进行循环利用时就可以跳过这个cell了。
    • 02搭建:实现tabelView的数据源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
    return 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    
    CXLClearCacheCell *cell = [tableView dequeueReusableCellWithIdentifier:setId];
 
    return cell;
}
  • 03.Cell的逻辑处理。

  • cell中在变化的就是存储的值,点击按钮时,还需要清除缓存。所以cell需要计算,那么在这里可以自定义cell,在自定义方法中计算缓存的大小。在点击清除缓存时,是有创建小菊花的,只是缓存的值不大,清除太快了就显示不出来了。

  • 初始化方法中添加小菊花

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        // 添加菊花
        UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
        
        // 开始动画
        [activityIndicator startAnimating];
        [self addSubview:activityIndicator];
        
        self.loadingView = activityIndicator;
        
        self.textLabel.text = @"清除缓存";
        [self getCacheSize];
    }
    return self;
}
  • 布局textLabel和菊花位置。
// 布局
- (void)layoutSubviews
{
    [super layoutSubviews];
    [self.textLabel sizeToFit];
    self.textLabel.centerY = self.height*0.5;
    self.loadingView.x = CGRectGetMaxX(self.textLabel.frame) + CXLMargin;
    self.loadingView.centerY = self.height*0.5;
}
  • 计算缓存大小。这个计算方法会在很多时候用到,所以我直接创建了一个分类来计算,这样在cell中直接调用就可以了。

    • 在字符串分类中暴露两个方法:1个是计算大小,1个是根据大小分类。
@interface NSString (Extension)
- (NSInteger)fileSize;
- (NSString *)fileSizeString;
@end
  • 方法实现
- (NSInteger)fileSize
{
    // 创建文件管理者
    NSFileManager *manager = [NSFileManager defaultManager];
    // 先判断文件是否存在
    BOOL isDirectory = NO;
    BOOL exist = [manager fileExistsAtPath:self isDirectory:&isDirectory];
    // 如果文件不存在
    if (exist==NO) return 0;
    
    // 如果文件存在  判断为文件夹还是文件
    if (isDirectory) {
        // 计算文件大小。拿到了完整路径
        NSInteger fileSize = 0;
        // 用完整路径查询所有的文件的大小,返回为数组
        NSArray *pathArray = [manager subpathsAtPath:self];
        
        // 遍历数组,将获得的数组字符串拼接到file上
        for (NSString *path in pathArray) {
            // 获得完整地址
            NSString *fulSubPath = [self stringByAppendingPathComponent:path];
            // 获得属性
            NSDictionary *attrs = [manager attributesOfItemAtPath:fulSubPath error:nil];
            // 过滤掉文件夹
            if ([attrs[NSFileType] isEqualToString:NSFileTypeDirectory]) continue;
            // 将属性中的fileSize相加。
            fileSize += [attrs[NSFileSize] integerValue];
    }
        return fileSize;

    }
    return [[manager attributesOfItemAtPath:self error:nil][NSFileSize] integerValue];
}
- (NSString *)fileSizeString
{
    NSInteger fileSize = self.fileSize;
    // 设定一个单位
    CGFloat unit = 1000.0;
    // 对fileSize进行判断
    if (fileSize>= unit * unit * unit) {
        return [NSString stringWithFormat:@"%.1fGB",fileSize/(unit*unit*unit)];
    }else if (fileSize>= unit*unit) {
        return [NSString stringWithFormat:@"%.1fMB",fileSize/(unit*unit)];
    }else if (fileSize>= unit){
        return [NSString stringWithFormat:@"%.1fKB",fileSize/unit];
    }else
    {
        return [NSString stringWithFormat:@"%zdB",fileSize];
    }
    
}
  • 在cell中调用.我采用的是异步,毕竟如果缓存非常大的话,计算也是比较耗时的,所以尽量不要占用主线程的时间。
// 获取缓存大小
- (void)getCacheSize
{
 dispatch_async(dispatch_get_global_queue(0, 0), ^{
        // 应用沙盒地址,返回的是一个数组
        NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
        // 拼接路径
        NSString *file = [caches stringByAppendingPathComponent:@"default/com.hackemist.SDWebImageCache.default"].fileSizeString;
         // 计算缓存大小只是为了在label中显示。
        NSString *str = [NSString stringWithFormat:@"清除缓存(%@)",file];
            dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主线程
        self.textLabel.text = str;
        [self.loadingView removeFromSuperview];   
        });      
    });
}
  • 在选中状态时清除缓存。在这里我直接用的SDWebImage中的清楚缓存的方法,如果你不想用到这个框架,可以利用一个异步方法,将fileManager清除。
    • 01利用一个异步函数,取出沙盒中的数据,remove掉。
   dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSString *cachPath = [ NSSearchPathForDirectoriesInDomains ( NSCachesDirectory , NSUserDomainMask , YES ) objectAtIndex : 0 ];
       
       NSArray *files = [[ NSFileManager defaultManager ] subpathsAtPath :cachPath];
       
       for ( NSString *p in files) {
           NSError *error;
           NSString *path = [cachPath stringByAppendingPathComponent :p];
           if ([[ NSFileManager defaultManager ] fileExistsAtPath :path]) {
               [[ NSFileManager defaultManager ] removeItemAtPath :path error :&error];
           }
       }dispatch_async(dispatch_get_main_queue(), ^{
        // 创建cell
       CXLClearCacheCell *cell = (CXLClearCacheCell *) [tableView cellForRowAtIndexPath:indexPath];
       // 取消遮盖
       [SVProgressHUD showSuccessWithStatus:@"清除缓存成功"];
          // 在cell中写的一个删除后的方法 
      [cell regist];
       });
  • 02利用SDWebImage只需要调用删除缓存方法就直接删除。
  // 清除缓存代码
    [[SDImageCache sharedImageCache] clearDiskOnCompletion:^{   
    // 创建cell
        CXLClearCacheCell *cell = (CXLClearCacheCell *) [tableView cellForRowAtIndexPath:indexPath];
       // 取消遮盖
        [SVProgressHUD showSuccessWithStatus:@"清除缓存成功"];       
        [cell regist];
   }];

你可能感兴趣的:(缓存与删除)