Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2024-04-11 - [Batch @Published Array Mutations]
**Learning:** Mutating individual elements of a `@Published` array inside a loop triggers a UI update for each change.
**Action:** For collections of value types, use functional methods like `.map` to batch updates into a single assignment, significantly reducing unnecessary UI recalculations.
40 changes: 32 additions & 8 deletions Sources/Cacheout/ViewModels/CacheoutViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,23 @@ class CacheoutViewModel: ObservableObject {
}

func selectAllSafe() {
for i in scanResults.indices where scanResults[i].category.riskLevel == .safe && !scanResults[i].isEmpty {
scanResults[i].isSelected = true
// Optimization: Batch @Published updates to avoid multiple UI view redraws
// Mutating individual elements of a @Published array inside a loop triggers a UI update for each change.
scanResults = scanResults.map { result in
var newResult = result
if result.category.riskLevel == .safe && !result.isEmpty {
newResult.isSelected = true
}
return newResult
}
}

func deselectAll() {
for i in scanResults.indices {
scanResults[i].isSelected = false
// Optimization: Batch @Published updates to avoid multiple UI view redraws
scanResults = scanResults.map { result in
var newResult = result
newResult.isSelected = false
return newResult
}
deselectAllNodeModules()
}
Expand All @@ -193,17 +202,32 @@ class CacheoutViewModel: ObservableObject {
}

func selectStaleNodeModules() {
for i in nodeModulesItems.indices where nodeModulesItems[i].isStale {
nodeModulesItems[i].isSelected = true
// Optimization: Batch @Published updates to avoid multiple UI view redraws
nodeModulesItems = nodeModulesItems.map { item in
var newItem = item
if item.isStale {
newItem.isSelected = true
}
return newItem
}
}

func selectAllNodeModules() {
for i in nodeModulesItems.indices { nodeModulesItems[i].isSelected = true }
// Optimization: Batch @Published updates to avoid multiple UI view redraws
nodeModulesItems = nodeModulesItems.map { item in
var newItem = item
newItem.isSelected = true
return newItem
}
}

func deselectAllNodeModules() {
for i in nodeModulesItems.indices { nodeModulesItems[i].isSelected = false }
// Optimization: Batch @Published updates to avoid multiple UI view redraws
nodeModulesItems = nodeModulesItems.map { item in
var newItem = item
newItem.isSelected = false
return newItem
}
}

/// Menu bar label: show free GB in the tray
Expand Down