From f10ca287ae2b61b332bf78db1f00d418f32b88d7 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2026 03:56:37 +0000 Subject: [PATCH] Offload blocking calls from MainActor to maintain UI responsiveness Co-authored-by: acebytes <2820910+acebytes@users.noreply.github.com> --- .../ViewModels/CacheoutViewModel.swift | 78 ++++++++++--------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/Sources/Cacheout/ViewModels/CacheoutViewModel.swift b/Sources/Cacheout/ViewModels/CacheoutViewModel.swift index 13a9811..702c9ae 100644 --- a/Sources/Cacheout/ViewModels/CacheoutViewModel.swift +++ b/Sources/Cacheout/ViewModels/CacheoutViewModel.swift @@ -147,7 +147,7 @@ class CacheoutViewModel: ObservableObject { func scan() async { isScanning = true isNodeModulesScanning = true - diskInfo = DiskInfo.current() + diskInfo = await Task.detached { DiskInfo.current() }.value // Scan caches and node_modules in parallel async let cacheResults = scanner.scanAll(CacheCategory.allCategories) @@ -229,48 +229,50 @@ class CacheoutViewModel: ObservableObject { isDockerPruning = true defer { isDockerPruning = false } - let process = Process() - let pipe = Pipe() - process.executableURL = URL(fileURLWithPath: "/bin/bash") - process.arguments = ["-c", "docker system prune -f 2>&1"] - process.standardOutput = pipe - process.standardError = pipe - process.environment = [ - "PATH": "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin", - "HOME": FileManager.default.homeDirectoryForCurrentUser.path - ] - - do { - try process.run() - process.waitUntilExit() - let data = pipe.fileHandleForReading.readDataToEndOfFile() - let output = String(data: data, encoding: .utf8) ?? "" - - if process.terminationStatus == 0 { - // Extract "Total reclaimed space:" line - if let line = output.components(separatedBy: "\n") - .first(where: { $0.contains("reclaimed") }) { - lastDockerPruneResult = line.trimmingCharacters(in: .whitespaces) + lastDockerPruneResult = await Task.detached { + let process = Process() + let pipe = Pipe() + process.executableURL = URL(fileURLWithPath: "/bin/bash") + process.arguments = ["-c", "docker system prune -f 2>&1"] + process.standardOutput = pipe + process.standardError = pipe + process.environment = [ + "PATH": "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin", + "HOME": FileManager.default.homeDirectoryForCurrentUser.path + ] + + do { + try process.run() + process.waitUntilExit() + let data = pipe.fileHandleForReading.readDataToEndOfFile() + let output = String(data: data, encoding: .utf8) ?? "" + + if process.terminationStatus == 0 { + // Extract "Total reclaimed space:" line + if let line = output.components(separatedBy: "\n") + .first(where: { $0.contains("reclaimed") }) { + return line.trimmingCharacters(in: .whitespaces) + } else { + return "Docker pruned successfully" + } } else { - lastDockerPruneResult = "Docker pruned successfully" - } - } else { - let lowerOutput = output.lowercased() - if lowerOutput.contains("cannot connect") || - lowerOutput.contains("is the docker daemon running") || - lowerOutput.contains("connection refused") || - lowerOutput.contains("no such file or directory") { - lastDockerPruneResult = "Docker must be running to prune" - } else { - lastDockerPruneResult = "Docker prune failed — is Docker running?" + let lowerOutput = output.lowercased() + if lowerOutput.contains("cannot connect") || + lowerOutput.contains("is the docker daemon running") || + lowerOutput.contains("connection refused") || + lowerOutput.contains("no such file or directory") { + return "Docker must be running to prune" + } else { + return "Docker prune failed — is Docker running?" + } } + } catch { + return "Docker not found" } - } catch { - lastDockerPruneResult = "Docker not found" - } + }.value // Refresh disk info after prune - diskInfo = DiskInfo.current() + diskInfo = await Task.detached { DiskInfo.current() }.value } func clean() async {