Skip to content

Commit 285fb7b

Browse files
committed
fix: cancel delayed UI tasks in course cache flows
1 parent cf3f13d commit 285fb7b

File tree

2 files changed

+24
-11
lines changed

2 files changed

+24
-11
lines changed

app/dauphin/View/Setting/ClearCacheView.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ struct ClearCacheView: View {
1111
@StateObject private var courseViewModel = CourseViewModel()
1212
@State private var showingClearCacheAlert = false
1313
@State private var cacheCleared = false
14+
@State private var clearTask: Task<Void, Never>?
1415

1516
var body: some View {
1617
VStack(spacing: 20) {
@@ -33,6 +34,9 @@ struct ClearCacheView: View {
3334
Text(
3435
"This will remove all cached course data. You'll need to refresh to reload your courses."
3536
)
37+
}.onDisappear {
38+
clearTask?.cancel()
39+
clearTask = nil
3640
}
3741
}
3842

@@ -41,8 +45,10 @@ struct ClearCacheView: View {
4145

4246
withAnimation(.spring()) { cacheCleared = true }
4347

44-
Task {
48+
clearTask?.cancel()
49+
clearTask = Task { @MainActor in
4550
try? await Task.sleep(nanoseconds: 3_000_000_000)
51+
guard !Task.isCancelled else { return }
4652
withAnimation { cacheCleared = false }
4753
}
4854
}

app/dauphin/ViewModels/CourseViewModel.swift

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import SwiftUI
2525
private var monitor: NWPathMonitor
2626
private let monitorQueue = DispatchQueue(label: "CourseViewModel.Network")
2727
private var isNetworkAvailable = true
28+
private var cacheMessageTask: Task<Void, Never>?
2829

2930
private var hasPerformedInitialLoad = false
3031

@@ -62,7 +63,19 @@ import SwiftUI
6263
startNetworkMonitor()
6364
}
6465

65-
deinit { monitor.cancel() }
66+
deinit {
67+
cacheMessageTask?.cancel()
68+
monitor.cancel()
69+
}
70+
71+
private func scheduleCacheMessageClear() {
72+
cacheMessageTask?.cancel()
73+
cacheMessageTask = Task { @MainActor [weak self] in
74+
try? await Task.sleep(nanoseconds: 2_000_000_000)
75+
guard !Task.isCancelled else { return }
76+
self?.cacheUpdateMessage = nil
77+
}
78+
}
6679

6780
private func startNetworkMonitor() {
6881
monitor.pathUpdateHandler = { [weak self] path in
@@ -111,6 +124,7 @@ import SwiftUI
111124
async
112125
{
113126
if forceRefresh { self.isRefreshing = true }
127+
cacheMessageTask?.cancel()
114128

115129
// 先載入快取顯示
116130
if let cached = loadCoursesFromCache(), !cached.isEmpty {
@@ -146,11 +160,7 @@ import SwiftUI
146160
self.isRefreshing = false
147161
self.cacheUpdateMessage =
148162
forceRefresh ? "Refreshed successfully" : "Course data updated"
149-
150-
Task { @MainActor [weak self] in
151-
try? await Task.sleep(nanoseconds: 2_000_000_000)
152-
self?.cacheUpdateMessage = nil
153-
}
163+
scheduleCacheMessageClear()
154164
} catch {
155165
self.isUpdatingCache = false
156166
self.isRefreshing = false
@@ -159,10 +169,7 @@ import SwiftUI
159169
self.errorMessage = "Failed to fetch courses."
160170
} else if forceRefresh {
161171
self.cacheUpdateMessage = "Refresh failed"
162-
Task { @MainActor [weak self] in
163-
try? await Task.sleep(nanoseconds: 2_000_000_000)
164-
self?.cacheUpdateMessage = nil
165-
}
172+
scheduleCacheMessageClear()
166173
}
167174
Self.logger.error("Fetch error: \(error.localizedDescription)")
168175
}

0 commit comments

Comments
 (0)