Skip to content
Merged
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
36 changes: 24 additions & 12 deletions WordPress/Classes/Utility/Media/ImageDownloader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,23 +106,25 @@ actor ImageDownloader {

private func data(for request: URLRequest, options: ImageRequestOptions) async throws -> Data {
let requestKey = request.urlRequest?.url?.absoluteString ?? ""
let task = tasks[requestKey] ?? ImageDataTask(task: Task {
let task = tasks[requestKey] ?? ImageDataTask(key: requestKey, Task {
try await self._data(for: request, options: options, key: requestKey)
})
task.downloader = self

let subscriptionID = UUID()
task.subscriptions.insert(subscriptionID)
tasks[requestKey] = task

return try await withTaskCancellationHandler {
try await task.task.value
} onCancel: {
Task {
await self.unsubscribe(subscriptionID, key: requestKey)
}
return try await task.getData(subscriptionID: subscriptionID)
}

fileprivate nonisolated func unsubscribe(_ subscriptionID: UUID, key: String) {
Task {
await _unsubscribe(subscriptionID, key: key)
}
}

private func unsubscribe(_ subscriptionID: UUID, key: String) {
private func _unsubscribe(_ subscriptionID: UUID, key: String) {
guard let task = tasks[key],
task.subscriptions.remove(subscriptionID) != nil,
task.subscriptions.isEmpty else {
Expand Down Expand Up @@ -151,14 +153,24 @@ actor ImageDownloader {
}

private final class ImageDataTask {
let key: String
var subscriptions = Set<UUID>()
var isCancelled = false
var task: Task<Data, Error>
let task: Task<Data, Error>
weak var downloader: ImageDownloader?

init(subscriptions: Set<UUID> = Set<UUID>(), task: Task<Data, Error>) {
self.subscriptions = subscriptions
init(key: String, _ task: Task<Data, Error>) {
self.key = key
self.task = task
}

func getData(subscriptionID: UUID) async throws -> Data {
try await withTaskCancellationHandler {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now called with no isolation, so hopefully it will skip the part of the runtime that crashes on iOS 18 betas.

try await task.value
} onCancel: { [weak self] in
guard let self else { return }
self.downloader?.unsubscribe(subscriptionID, key: self.key)
}
}
}

// MARK: - ImageDownloader (Closures)
Expand Down