How to use withTaskCancellationHandler properly?

This now produces a warning with the Xcode 13.3 beta:

Capture of 'onCancel' with non-sendable type '() -> Void?' in a `@Sendable` closure

The best workaround I have come up with so far is to use an unchecked Sendable class to hold the cancellable object:

private class URLSessionDataTaskHolder: @unchecked Sendable {
    var task: URLSessionDataTask?
    func cancel() { task?.cancel() }
}

func data(for request: URLRequest) async throws -> (Data, URLResponse) {
    let dataTaskHolder = URLSessionDataTaskHolder()

    return try await withTaskCancellationHandler(
        handler: {
            dataTaskHolder.cancel()
        },
        operation: {
            try await withCheckedThrowingContinuation { continuation in
                let dataTask = self.dataTask(with: request) { data, response, error in
                    guard let data = data, let response = response else {
                        let error = error ?? URLError(.badServerResponse)
                        return continuation.resume(throwing: error)
                    }

                    continuation.resume(returning: (data, response))
                }

                dataTask.resume()
                dataTaskHolder.task = dataTask
            }
        }
    )
}

Are there better solutions here that I may be missing?

1 Like