In Xcode 11 beta 5 or 6 my existing code that relied on URLSession.DataTaskPublisher
stopped working. It seems like DataTaskPublisher
is never publishing any values but I can't work out why.
I've tried with .sink
and .handleEvents
as subscribers. I've tested .sink with a Just
publisher and confirmed it receives a value there.
I've also tried both giving the DataTaskPublisher
a URL
and giving it a URLRequest
. I've tried a request to an API including an authorization header, as well as basic requests to google.com and apple.com. I've tried using URLSession.shared
and creating a new instance of URLSession
. I've also tried with and without map
and decode
operators.
I've used XCTest
expectations to confirm that the test times out every single time, even if I give it a 4-minute timeout.
I just made a new example project and replicated the problem with the following code in the root view controller:
override func viewDidLoad() {
super.viewDidLoad()
print("view did load")
URLSession.shared.dataTaskPublisher(for: URL(string: "http://apple.com")!)
.handleEvents(receiveSubscription: { (sub) in
print(sub)
}, receiveOutput: { (response) in
print(response)
}, receiveCompletion: { (completion) in
print(completion)
}, receiveCancel: {
print("cancel")
}, receiveRequest: { (demand) in
print(demand)
})
}
The project prints "view did load" but nothing else ever prints. Any ideas about where I'm going wrong here? Thanks!
A publisher that delivers the results of performing URL session data tasks.
Overview. The URLSession class and related classes provide an API for downloading data from and uploading data to endpoints indicated by URLs. Your app can also use this API to perform background downloads when your app isn't running or, in iOS, while your app is suspended.
For basic requests, the URLSession class provides a shared singleton session object that gives you a reasonable default behavior for creating tasks. Use the shared session to fetch the contents of a URL to memory with just a few lines of code.
Before we start, we need to define the URL of the remote image. import UIKit let url = URL(string: "https://bit.ly/2LMtByx")! The next step is creating a data task, an instance of the URLSessionDataTask class. A task is always tied to a URLSession instance.
I think that there are two problems with your code, firstly you only have a publisher (handleEvent returns a publisher) and secondly that publisher goes out of scope and disappears. This works although it isn't exactly elegant.
import Combine
import SwiftUI
var pub: AnyPublisher<(data: Data, response: URLResponse), URLError>? = nil
var sub: Cancellable? = nil
var data: Data? = nil
var response: URLResponse? = nil
func combineTest() {
guard let url = URL(string: "https://apple.com") else {
return
}
pub = URLSession.shared.dataTaskPublisher(for: url)
.print("Test")
.eraseToAnyPublisher()
sub = pub?.sink(
receiveCompletion: { completion in
switch completion {
case .finished:
break
case .failure(let error):
fatalError(error.localizedDescription)
}
},
receiveValue: { data = $0.data; response = $0.response }
)
}
struct ContentView: View {
var body: some View {
Button(
action: { combineTest() },
label: { Text("Do It").font(.largeTitle) }
)
}
}
I did it in SwiftUI so that I would have less to worry about and I used 3 variables so that I could follow better. You need to use the 2 parameter sink as the publisher's error isn't Never. Finally the print() is just for test and works really well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With