6

Here is my pipeline:

URLSession.shared
      .dataTaskPublisher(for: urlRequest)
      .map { $0.data }
      .mapError { ...... }
      .eraseToAnyPublisher()
      .decode(type: MyObject.self, decoder: JSONDecoder())
      .receive(on: RunLoop.main)
      .catch { [weak self] error -> Just<MyObject> in
        guard let self = self else { return Just(emptyPayload) }
        self.hasError = true
        return Just(emptyPayload)
    }
    .sink(
      receiveCompletion: { [weak self] _ in
        print("i'm here")
      },
      receiveValue: { [weak self] value in
        print("value")
      }
    )

Why is sink never called?

Gil Birman
  • 35,242
  • 14
  • 75
  • 119
user1366265
  • 1,306
  • 1
  • 17
  • 28
  • I don't think this can be related to Xcode 11.3 in any way... – Renetik Dec 11 '19 at 20:14
  • 2
    `sink` returns a cancellable that you need to store somewhere, otherwise the request gets canceled as soon as it goes out of scope. There should be a warning on that line – dan Dec 11 '19 at 21:01

1 Answers1

9

dataTaskPublisher(for: urlRequest) will send values asynchronously. When program execution leaves your current scope, there are no more references to your pipeline and ARC destroys your pipeline before the network request has completed.

Your pipeline returns a Cancellable. Either assign that Cancellable directly to an instance variable or add the store(in:) operator to your pipeline.

Also worth mentioning is that if you mess around with Combine pipelines in an Xcode playground, your pipelines may live longer than you'd expect because the Playground tries to be smart about holding on to references for the sake of making experimentation easier. See this answer for an async example you can run in a playground, even though it applies neither of the fixes I mentioned.

Gil Birman
  • 35,242
  • 14
  • 75
  • 119