APP清除缓存功能的具体实现

sufangqi 7年前
   <p>几乎每一个 App 都有清除缓存的功能, 不然沙盒中的文件太多, 是很占用用户的资源的, 一个简单的清除缓存的功能我们可以单独用一个类来实现.</p>    <p>清除缓存的功能说白了就是讲沙盒中的 Cache 文件夹中的所有子文件和子文件夹全部删除, 在项目当中, 还需要向用户展示缓存的大小, 这就涉及到要计算文件的大小.</p>    <p>所以, 我们的任务就是, 计算沙盒中 Cache 文件的大小, 并将其子文件和子文件夹删除</p>    <ul>     <li> <p>首先我们建一个工具类</p> </li>    </ul>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/efff31a37e73decf77686d6c05fa5917.png"></p>    <p>清除缓存工具类</p>    <ul>     <li> <p>我们在工具类中建一个单例方法</p> </li>    </ul>    <pre>  + (instancetype)yf_sharedManager {      static YFWipeCacheManager *manager;      static dispatch_once_t onceToken;      dispatch_once(&onceToken, ^{          manager = [[YFWipeCacheManager alloc] init];      });      return manager;  }</pre>    <ul>     <li> <p>暴露一个对象方法, 根据路径计算文件大小</p> <p>其实我们这个类的目的除了清除缓存之外, 还有一个功能就是可以计算任何路径下的文件及文件夹的大小</p> </li>    </ul>    <pre>  #pragma mark - 计算单个文件的大小  - (CGFloat)yf_fileSizeAtPath:(NSString *)path {       /* 如果这个路径文件存在的话, 就计算出文件的大小并返回, 否则就返回0 */      if ([kFileManager fileExistsAtPath:path]) {          unsigned long long size = [kFileManager attributesOfItemAtPath:path error:NULL].fileSize;          return size / 1024.0 / 1024.0;      }      return 0;  }</pre>    <ul>     <li> <p>计算缓存文件夹中的文件大小</p> <p>因为苹果没有提供 API 直接计算文件夹的大小, 那么我们就需要遍历整个文件夹,来计算文件夹下单个文件的大小</p> </li>    </ul>    <pre>  #pragma mark - 计算缓存文件夹的大小   /* 因为苹果没有提供 API 直接计算文件夹的大小, 那么我们就需要遍历整个文件夹,来计算文件夹下单个文件的大小 */  - (CGFloat)yf_cacheSize {      /* 先将属性 cacheSize 的大小置为0,这样每次计算的文件夹大小的时候就不会重复累加 */      self.cacheSize = 0;      NSDirectoryEnumerator *enumerator = [kFileManager enumeratorAtPath:kCachePath];      __weak typeof(self)weakSelf = self;       /* 遍历 cache 文件夹路径中的子路径,然后计算每单个文件的大小,累加后返回 */      [enumerator.allObjects enumerateObjectsUsingBlock:^(NSString *subPath, NSUInteger idx, BOOL * _Nonnull stop) {          NSString *path = [kCachePath stringByAppendingPathComponent:subPath];          weakSelf.cacheSize += [self yf_fileSizeAtPath:path];      }];      return self.cacheSize;  }</pre>    <ul>     <li> <p>计算其他文件夹的大小</p> <p>方法同计算 cache 文件夹大小一样</p> </li>    </ul>    <pre>  #pragma mark - 计算其他文件夹的大小    /* 方法同计算 cache 文件夹大小 */  - (CGFloat)yf_folderSizeAtPath:(NSString *)path {      CGFloat folderSize = 0;      __block CGFloat blockFolderSize = folderSize;      if ([kFileManager fileExistsAtPath:path]) {          NSDirectoryEnumerator *enumerator = [kFileManager enumeratorAtPath:path];          [enumerator.allObjects enumerateObjectsUsingBlock:^(NSString *subPath, NSUInteger idx, BOOL * _Nonnull stop) {              NSString *absolutePath = [path stringByAppendingPathComponent:subPath];              blockFolderSize += [self yf_fileSizeAtPath:absolutePath];          }];          return folderSize;      }      return 0;  }</pre>    <ul>     <li> <p>我们除了要计算缓存文件的大小, 最重要的是要删除这些缓存文件</p> <p>清除缓存文件是一个耗时操作, 我们需要开启一个异步操作, 即开启子线程</p> </li>    </ul>    <pre>  #pragma mark - 清除缓存文件  - (void)yf_wipeCacheAction {       /* 清除缓存文件是一个耗时操作, 我们需要开启一个异步操作 */      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{           /* 在这个 block 中, 方法跟计算 cache 文件夹的大小一样, 只不过最后是清除文件 */          NSDirectoryEnumerator *enumerator = [kFileManager enumeratorAtPath:kCachePath];          [enumerator.allObjects enumerateObjectsUsingBlock:^(NSString *subPath, NSUInteger idx, BOOL * _Nonnull stop) {              /* 错误处理 */              NSError *error = nil;              NSString *path = [kCachePath stringByAppendingPathComponent:subPath];              if ([kFileManager fileExistsAtPath:path]) {                  [kFileManager removeItemAtPath:path error:&error];                  if (error) {                      NSLog(@"文件删除失败");                  }else {                      NSLog(@"文件删除成功");                  }              }          }];      });  }</pre>    <ul>     <li> <p>在实际的项目中, 我们可以暴露一个类方法, 实现一键式地清除缓存</p> <p>包含以下几个步骤</p> <p>1.弹出蒙版, 计算缓存文件夹的大小</p> <p>2.弹出提示框, 提示用户是否要清除缓存</p> <p>3.当用户点击取消按钮时,不做任何操作</p> <p>4.当用户点击确定按钮时,清除缓存,并提示用户缓存清除成功</p> </li>    </ul>    <pre>  #pragma mark - 最后暴露一个类方法, 只要调用这个,自动弹出清除缓存提示框, 需要同 MBProgressHud 配合使用    + (void)yf_wipeCacheWithDefaultStyle {      MBProgressHUD *hud = [MBProgressHUD showHudTo:kTopStackController.view image:nil text:@"正在计算缓存大小" animated:YES];       /* 由于计算缓存大小也是一个耗时操作. 我们做一个延时. 来确保获取到数据 */      __weak typeof(self)weakSelf = self;      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{          UIAlertController *alterVC = [UIAlertController alertControllerWithTitle:@"清除缓存" message:[NSString stringWithFormat:@"APP当前的缓存为:%.2fM",[[weakSelf yf_sharedManager] yf_cacheSize]] preferredStyle:UIAlertControllerStyleActionSheet];          UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {              [kTopStackController dismissViewControllerAnimated:YES completion:nil];          }];          UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {              [[weakSelf yf_sharedManager] yf_wipeCacheAction];              MBProgressHUD *clearHud = [MBProgressHUD showHudTo:kTopStackController.view image:nil text:@"清除成功" animated: YES];              clearHud.mode = MBProgressHUDModeText;              [clearHud hide:YES afterDelay:2.0];          }];          [alterVC addAction:cancelAction];          [alterVC addAction:confirmAction];          [kTopStackController presentViewController:alterVC animated:YES completion:nil];      });      [hud hide:YES afterDelay:1.0];  }</pre>    <p>所以这个类最基础的使用方法就是在按钮的点击事件中加入这样一句代码</p>    <pre>  [YFWipeCacheManager yf_wipeCacheWithDefaultStyle];</pre>    <p>不过有一点不方便的是, 必须要和 MBProgressHUD 这个第三方框架联合使用, 如果大家不想这么做的话, 也无需理会, 用这个类中的其他方法配合自定义, 也能够实现类似的效果.</p>    <p>下面就是实现的效果图:</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/181d583ff91c504c0421322769bbc28c.gif"></p>    <p style="text-align: center;">清除缓存实现效果图</p>    <p> </p>    <p> </p>    <p>来自:http://www.jianshu.com/p/b2619155504f</p>    <p> </p>