Skip to content

Commit 17cbf2d

Browse files
committed
Remove ActorBox and harden background task cleanup
1 parent 9b102a0 commit 17cbf2d

File tree

4 files changed

+44
-66
lines changed

4 files changed

+44
-66
lines changed

Sources/Cache/ImageCache.swift

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -868,31 +868,43 @@ open class ImageCache: @unchecked Sendable {
868868
@objc public func backgroundCleanExpiredDiskCache() {
869869
// if 'sharedApplication()' is unavailable, then return
870870
guard let sharedApplication = KingfisherWrapper<UIApplication>.shared else { return }
871-
872-
let taskActor = ActorBox<UIBackgroundTaskIdentifier?>(nil)
873-
874-
let createdTask = sharedApplication.beginBackgroundTask(withName: "Kingfisher:backgroundCleanExpiredDiskCache") {
875-
Task {
876-
guard let bgTask = await taskActor.value, bgTask != .invalid else { return }
877-
sharedApplication.endBackgroundTask(bgTask)
878-
await taskActor.setValue(.invalid)
871+
872+
actor BackgroundTaskState {
873+
private var value: UIBackgroundTaskIdentifier? = nil
874+
875+
func setValue(_ newValue: UIBackgroundTaskIdentifier) {
876+
value = newValue
877+
}
878+
879+
func takeValidValueAndInvalidate() -> UIBackgroundTaskIdentifier? {
880+
guard let task = value, task != .invalid else { return nil }
881+
value = .invalid
882+
return task
879883
}
880884
}
881-
882-
cleanExpiredDiskCache {
883-
Task {
884-
guard let bgTask = await taskActor.value, bgTask != .invalid else { return }
885+
886+
let taskState = BackgroundTaskState()
887+
888+
func endBackgroundTaskIfNeeded() {
889+
Task { @MainActor in
890+
guard let bgTask = await taskState.takeValidValueAndInvalidate() else { return }
885891
#if compiler(>=6)
886892
sharedApplication.endBackgroundTask(bgTask)
887893
#else
888894
await sharedApplication.endBackgroundTask(bgTask)
889895
#endif
890-
await taskActor.setValue(.invalid)
891896
}
892897
}
893-
894-
Task {
895-
await taskActor.setValue(createdTask)
898+
899+
let createdTask = sharedApplication.beginBackgroundTask(
900+
withName: "Kingfisher:backgroundCleanExpiredDiskCache",
901+
expirationHandler: endBackgroundTaskIfNeeded
902+
)
903+
904+
Task { await taskState.setValue(createdTask) }
905+
906+
cleanExpiredDiskCache {
907+
endBackgroundTaskIfNeeded()
896908
}
897909
}
898910
#endif

Sources/Utility/Box.swift

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,3 @@ class Box<T> {
3232
self.value = value
3333
}
3434
}
35-
36-
actor ActorBox<T> {
37-
var value: T
38-
init(_ value: T) {
39-
self.value = value
40-
}
41-
42-
func setValue(_ value: T) {
43-
self.value = value
44-
}
45-
}

Tests/KingfisherTests/KingfisherManagerTests.swift

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,31 +1243,25 @@ class KingfisherManagerTests: XCTestCase {
12431243

12441244
stub(url, data: testImageData)
12451245

1246-
let task = ActorBox<DownloadTask?>(nil)
1247-
1248-
let called = ActorBox(false)
1246+
let task = LockIsolated<DownloadTask?>(nil)
1247+
let callbackCount = LockIsolated(0)
12491248

12501249
let t: DownloadTask? = manager.retrieveImage(with: url) { result in
1251-
Task {
1252-
let calledResult = await called.value
1253-
XCTAssertFalse(calledResult)
1254-
XCTAssertNotNil(result.value?.image)
1255-
1256-
if !calledResult {
1257-
Task {
1258-
await task.value?.cancel()
1259-
}
1260-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
1261-
exp.fulfill()
1262-
}
1263-
} else {
1264-
XCTFail("Callback should not be invoked again.")
1265-
}
1250+
let count = callbackCount.withValue { value in
1251+
value += 1
1252+
return value
1253+
}
1254+
1255+
XCTAssertEqual(count, 1, "Callback should not be invoked again.")
1256+
XCTAssertNotNil(result.value?.image)
1257+
1258+
task.value?.cancel()
1259+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
1260+
exp.fulfill()
12661261
}
12671262
}
1268-
Task {
1269-
await task.setValue(t)
1270-
}
1263+
1264+
task.setValue(t)
12711265
waitForExpectations(timeout: 3, handler: nil)
12721266
}
12731267

@@ -1789,17 +1783,6 @@ struct SimpleImageDataProvider: ImageDataProvider, @unchecked Sendable {
17891783
struct E: Error {}
17901784
}
17911785

1792-
actor ActorBox<T> {
1793-
var value: T
1794-
init(_ value: T) {
1795-
self.value = value
1796-
}
1797-
1798-
func setValue(_ value: T) {
1799-
self.value = value
1800-
}
1801-
}
1802-
18031786
actor ActorArray<Element> {
18041787
var value: [Element]
18051788
init(_ value: [Element]) {

Tests/KingfisherTests/RetryStrategyTests.swift

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,6 @@ class RetryStrategyTests: XCTestCase {
215215

216216
func testDelayRetryStrategyDidRetried() {
217217
let exp = expectation(description: #function)
218-
let called = ActorBox(false)
219218
let source = Source.network(URL(string: "url")!)
220219
let retry = DelayRetryStrategy(maxRetryCount: 3, retryInterval: .seconds(0))
221220
let context = RetryContext(
@@ -227,12 +226,7 @@ class RetryStrategyTests: XCTestCase {
227226
XCTFail("The decision should be `retry`.")
228227
return
229228
}
230-
Task {
231-
await called.setValue(true)
232-
let result = await called.value
233-
XCTAssertTrue(result)
234-
exp.fulfill()
235-
}
229+
exp.fulfill()
236230
}
237231

238232
waitForExpectations(timeout: 3, handler: nil)

0 commit comments

Comments
 (0)