From 13653b4995f702eda1d8ed63fe0766f9e0e371fb Mon Sep 17 00:00:00 2001 From: Kieran Klukas Date: Mon, 23 Mar 2026 22:54:49 -0400 Subject: [PATCH] feat: interleave loading front and behind --- cull/Services/ThumbnailCache.swift | 10 ++++++++-- cull/Views/PhotoViewer.swift | 23 +++++++++++++++++------ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/cull/Services/ThumbnailCache.swift b/cull/Services/ThumbnailCache.swift index 72fde26..5122574 100644 --- a/cull/Services/ThumbnailCache.swift +++ b/cull/Services/ThumbnailCache.swift @@ -7,6 +7,7 @@ final class ThumbnailCache { private let memoryCache = NSCache() private let previewCache = NSCache() private var previewKeys = Set() + private var preloadTask: Task? private let diskCacheURL: URL private let maxPixelSize: Int @@ -206,7 +207,10 @@ final class ThumbnailCache { } /// Fire-and-forget: preload previews in background. Used during navigation. + /// Cancels any previous preload so stale work doesn't compete. func preloadPreviews(photos: [Photo]) { + preloadTask?.cancel() + let work: [(String, URL)] = photos.compactMap { photo in let key = photo.url.absoluteString guard previewCache.object(forKey: key as NSString) == nil else { return nil } @@ -216,13 +220,15 @@ final class ThumbnailCache { let pc = previewCache - Task.detached(priority: .utility) { + preloadTask = Task.detached(priority: .utility) { for batchStart in stride(from: 0, to: work.count, by: 4) { + guard !Task.isCancelled else { return } let batch = Array(work[batchStart..