3

When attempting to send a background request with URLSession's dataTaskPublisher method:

URLSession(configuration: URLSessionConfiguration.background(withIdentifier: "example")) 
     .dataTaskPublisher(for: URL(string: "https://google.com")!) 
     .map(\.data) 
     .sink(receiveCompletion: { print($0) }) { print($0) }

I receive the error

Completion handler blocks are not supported in background sessions. Use a delegate instead.

This makes sense to me, sink is a bunch of completion handlers. So, I tried to build a Subscriber:

class ExampleSubscriber: Subscriber {
    typealias Input = Data

    typealias Failure = URLError

    func receive(subscription: Subscription) {
        subscription.request(.max(1))
    }

    func receive(_ input: Data) -> Subscribers.Demand {
        print(input)

        return Subscribers.Demand.none
    }

    func receive(completion: Subscribers.Completion<URLError>) {}

}

and subscribe with the Subscriber:

URLSession(configuration: URLSessionConfiguration.background(withIdentifier: "example"))
    .dataTaskPublisher(for: URL(string: "https://google.com")!)
    .map(\.data)
    .subscribe(ExampleSubscriber())

and I receive the same error:

Completion handler blocks are not supported in background sessions. Use a delegate instead.

Is it possible to perform a background request using dataTaskPublisher or do I have to use a delegate to URLSession?

Emma K Alexandra
  • 464
  • 3
  • 15
  • This might help: https://stackoverflow.com/a/44208460/968155 – New Dev May 30 '20 at 21:04
  • @NewDev Yeah, I know when using say `dataTask`, you can't use completion handlers and a background session at the same time. I'm specifically asking if it's possible to use Combine and a background session. Particularly when adding a specific `Subscriber`, it seems analogous to a delegate. But I get that it might just not be possible. – Emma K Alexandra May 30 '20 at 21:49
  • 1
    You can’t use `DataTaskPublisher` with background session, as it uses completion handler behind the scenes. You could, obviously just create your own that uses a delegate implementation, but the whole idea of background session is that these are requests that survive not the suspending of the app, but also the app being jettisoned in the natural course of its lifecycle. So when requests are done, OS fires up your app, and neither completion blocks nor combine publishers created before app was suspended exist any more. So it just doesn’t quite make sense to use Combine with background session. – Rob May 30 '20 at 22:14

1 Answers1

3

URLSession.DataTaskPublisher is built on top of URLSessionDataTask and sets a completion handler on the task. So you cannot use DataTaskPublisher with a background session.

You can find the source code of DataTaskPublisher in the Swift project repo. Here are the relevant lines:

let task = p.session.dataTask(
    with: p.request,
    completionHandler: handleResponse(data:response:error:)
)
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
rob mayoff
  • 375,296
  • 67
  • 796
  • 848