// // AppCacheManager.swift // QuickLocation // // Created by 八条 on 2026/6/11. // import Foundation final class AppCacheManager { // MARK: - 计算单个文件夹大小(字节) static func folderSize(at path: String) -> Int64 { guard FileManager.default.fileExists(atPath: path) else { return 0 } var totalSize: Int64 = 0 let manager = FileManager.default guard let filePaths = try? manager.subpaths(atPath: path) else { return totalSize } for subPath in filePaths { let fullPath = path + "/" + subPath var isDir: ObjCBool = false if manager.fileExists(atPath: fullPath, isDirectory: &isDir) { if isDir.boolValue { totalSize += folderSize(at: fullPath) } else { // 读取文件属性,失败则跳过 if let attrs = try? manager.attributesOfItem(atPath: fullPath) { totalSize += attrs[.size] as? Int64 ?? 0 } } } } return totalSize } // MARK: - 获取 App 总缓存大小(Caches + tmp) static func totalCacheSize() -> Int64 { let cachesPath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first ?? "" let tmpPath = NSTemporaryDirectory() let cachesSize = folderSize(at: cachesPath) let tmpSize = folderSize(at: tmpPath) return cachesSize + tmpSize } // MARK: - 字节 转 可读字符串(B/KB/MB/GB) static func formatByte(_ byte: Int64) -> String { guard byte > 0 else { return "0 B" } let units: [String] = ["B", "KB", "M", "G"] var size = Double(byte) var unitIndex = 0 while size >= 1024, unitIndex < units.count - 1 { size /= 1024 unitIndex += 1 } return String(format: "%.2f %@", size, units[unitIndex]) } // MARK: - 清理缓存(Caches + tmp) static func clearCache(completion: @escaping () -> Void) { DispatchQueue.global(qos: .background).async { let manager = FileManager.default // 清理 Caches let cachesPath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first ?? "" try? manager.removeItem(atPath: cachesPath) try? manager.createDirectory(atPath: cachesPath, withIntermediateDirectories: true) // 清理 tmp let tmpPath = NSTemporaryDirectory() let tmpFiles = (try? manager.contentsOfDirectory(atPath: tmpPath)) ?? [] tmpFiles.forEach { file in try? manager.removeItem(atPath: tmpPath + file) } DispatchQueue.main.async { completion() } } } }