原谅我比较懒~
清除缓存功能一般是以UITableView的cell显示在界面的,所以这里写一个UITableViewCell的类。使用时在tableView的viewDidLoad()
方法中注册该自定义cell,然后到tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
方法中取即可。
该功能实现需要解决两点
- 计算文件大小并显示出来
缓存文件较大的话,计算起来是比较费时的,所以需要用到异步操作,然后回到主线程更新UI ,在swift3.0中,线程的使用和之前有些不同,但不过是更像swift风格而已,以下给出示例代码。 - 删除文件
对于我来说,缓存文件分为两种,一种是用SDWebImage框架下载的图片,一种是自己存放的缓存文件,框架缓存的文件可以直接使用框架API删除,自定义的缓存文件需要传入文件地址手动删除。
至于实现上,我对String类扩展了两个方法,计算文件或文件夹大小和删除文件或文件夹,然后自定义一个UITableViewCell的子类。
** AllCleanCacheCell**
import UIKit
import SDWebImage
import SVProgressHUD
class AllCleanCacheCell: UITableViewCell {
// 自定义的缓存文件路径 (可为nil)
var customCachePath: String?
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// 指示器
let activityIndicator = UIActivityIndicatorView.init(activityIndicatorStyle: .gray)
activityIndicator.startAnimating()
self.accessoryView = activityIndicator
// 设置默认文字
self.textLabel?.text = "清除缓存(正在计算缓存大小)"
// 设置禁止点击
self.isUserInteractionEnabled = false
weak var weakSelf = self
// 开启子线程 计算缓存大小
DispatchQueue.global().async {
// 子线程计算文件大小
var size: UInt64 = 0
size = UInt64(SDImageCache.shared().getSize())
if self.customCachePath != nil {
size += (self.customCachePath?.getFileSize())!
}
if weakSelf == nil {
print("cell被销毁 直接退出执行")
return
}
var tempSize: Double = 0.0
var stringSize = ""
if size > UInt64(pow(10.0, 9)) {
tempSize = Double(size) / pow(10.0, 9)
stringSize = String(format: "%.2fGB", tempSize)
} else if size > UInt64(pow(10.0, 6)){
tempSize = Double(size) / pow(10.0, 6)
stringSize = String(format: "%.2fMB", tempSize)
} else if size > UInt64(pow(10.0, 3)) {
tempSize = Double(size) / pow(10.0, 3)
stringSize = String(format: "%.2fKB", tempSize)
} else {
tempSize = Double(size)
stringSize = String(format: "%.2fB", tempSize)
}
// 主线程更新UI
DispatchQueue.main.async {
// 设置cell文字
weakSelf?.textLabel?.text = "清除缓存(\(stringSize))"
weakSelf?.accessoryView = nil
weakSelf?.accessoryType = .disclosureIndicator
// 添加手势监听器 并恢复点击事件
weakSelf?.isUserInteractionEnabled = true
weakSelf?.addGestureRecognizer(UITapGestureRecognizer.init(target: self, action: #selector(self.cacheCellClick)))
}
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// 捕获点击事件,清除缓存
func cacheCellClick() {
SVProgressHUD.show(withStatus: "正在清除缓存...")
SVProgressHUD.setDefaultMaskType(.black)
// 删除缓存
SDImageCache.shared().clearDisk {
DispatchQueue.global().async {
// 线程休眠2秒
Thread.sleep(forTimeInterval: 2)
if self.customCachePath != nil {
// 调用自定义的删除文件的String类扩展方法
self.customCachePath?.removeFileOfString()
// 再将文件夹创建出来
do {
try FileManager.default.createDirectory(atPath: self.customCachePath!, withIntermediateDirectories: true, attributes: nil)
} catch {
print("error :\(error)")
}
}
DispatchQueue.main.async {
SVProgressHUD.dismiss()
self.textLabel?.text = "清除缓存(0.00B)"
}
}
}
}
override func layoutSubviews() {
super.layoutSubviews()
// cell被从缓存池中取出时会调用
let activityIndicator = self.accessoryView as? UIActivityIndicatorView // 如果已经计算完毕,那么self.accessoryView就为nil ,此时这2步操作无效
activityIndicator?.startAnimating()
}
}
String扩展
import UIKit
// 扩展String 计算文件或文件夹大小
extension String {
// 对象方法
func getFileSize() -> UInt64 {
var size: UInt64 = 0
let fileManager = FileManager.default
var isDir: ObjCBool = false
let isExists = fileManager.fileExists(atPath: self, isDirectory: &isDir)
// 判断文件存在
if isExists {
// 是否为文件夹
if isDir.boolValue {
// 迭代器 存放文件夹下的所有文件名
let enumerator = fileManager.enumerator(atPath: self)
for subPath in enumerator! {
// 获得全路径
let fullPath = self.appending("/\(subPath)")
do {
let attr = try fileManager.attributesOfItem(atPath: fullPath)
size += attr[FileAttributeKey.size] as! UInt64
} catch {
print("error :\(error)")
}
}
} else { // 单文件
do {
let attr = try fileManager.attributesOfItem(atPath: self)
size += attr[FileAttributeKey.size] as! UInt64
} catch {
print("error :\(error)")
}
}
}
return size
}
func removeFileOfString() {
let fileManager = FileManager.default
let isExists = fileManager.fileExists(atPath: self)
if isExists {
do {
try fileManager.removeItem(atPath: self)
} catch {
print("error :\(error)")
}
} else {
print("文件或文件夹不存在")
}
}
}
使用方法
在控制器的viewDidLoad()
方法中注册该cell ,在缓存池中凭借标识符取出该类型的cell
viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
// 注册cell (AllCleanCacheCell为自定义cell的类名)
self.tableView.register(AllCleanCacheCell.self, forCellReuseIdentifier: "cache")
}
实现UITableView的代理方法
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cache")
return cell!
}