diff --git a/Meshtastic/Router/Router.swift b/Meshtastic/Router/Router.swift index 5af2dfc8..61a599c2 100644 --- a/Meshtastic/Router/Router.swift +++ b/Meshtastic/Router/Router.swift @@ -45,6 +45,7 @@ class Router: ObservableObject { // MARK: Node Object ID Cache /// In-memory cache mapping node numbers to their Core Data `NSManagedObjectID` for O(1) lookups. + /// Thread-safe by virtue of Router's @MainActor isolation — all access is on the main thread. private var nodeObjectIDCache: [Int64: NSManagedObjectID] = [:] /// Updates the node cache from a set of fetched nodes. Call this when the node list changes. diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index 5bcf47e7..798e4d6e 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -11,6 +11,9 @@ import CoreData import Foundation struct NodeList: View { + /// Debounce delay for node selection changes (100ms) + private static let nodeSelectionDebounceNs: UInt64 = 100_000_000 + @Environment(\.managedObjectContext) var context @EnvironmentObject var accessoryManager: AccessoryManager @StateObject var router: Router @@ -125,11 +128,11 @@ struct NodeList: View { } } .onChange(of: router.nodeListSelectedNodeNum) { _, newNum in - // Debounce rapid route changes — only process the last selection after 100ms + // Debounce rapid route changes — only process the last selection after a short delay nodeSelectionTask?.cancel() nodeSelectionTask = Task { do { - try await Task.sleep(nanoseconds: 100_000_000) + try await Task.sleep(nanoseconds: Self.nodeSelectionDebounceNs) } catch { return // Cancelled by a newer selection }