8

How to convert:

func getResults(completion: ([Result]?, Error) -> Void)

Into

var resultsPublisher: AnyPublisher<[Result], Error>

Just a scheme how I see it is (this syntax doesn't exist):

var resultsPublisher: AnyPublisher<[Result], Error> {
  let publisher: AnyPublisher = ... // init
  getResults { results, error in
     guard let results = results else {
       publisher.produce(error: error) // this syntax doesn't exist
       return
     }

     publisher.produce(results: results)  // this syntax doesn't exist

  }

  return publisher
}

I need that because some 3d party SDKs use completion closures and I want to write extensions to them that return Publishers.

Paul T.
  • 4,938
  • 7
  • 45
  • 93
  • 1
    Just wrap it in a Future. I just spent the day doing this very thing! See http://www.apeth.com/UnderstandingCombine/publishers/publishersfuture.html – matt May 17 '20 at 03:30
  • Thank you! Could you post your answer? I'll mark it as a correct, so it will help anybody in future – Paul T. May 17 '20 at 03:50
  • You have not given enough info for me to write an actual code answer, and the matter is very elementary and obvious. But it’s fine for you to answer your own question! – matt May 17 '20 at 08:12

1 Answers1

18

The answer is Future Publisher as matt explained:

var resultsPublisher: AnyPublisher<[Result], Error> {
    // need deferred when want 
    // to start request only when somebody subscribes 
    // + without Deferred it's impossible to .retry() later
    Deferred { 
        Future { promise in
           self.getResults { results, error in
              guard let results = results else {
                 promise(.failure(error))
                 return
              }

              promise(.success(results))
           }
         }
    }
    .eraseToAnyPublisher()
}
Paul T.
  • 4,938
  • 7
  • 45
  • 93
  • One idea: put a breakpoint on the first line of `getResults` and make sure it is being called only when you expect it. Sometime a Future needs to be wrapped in a Deferred and I can’t tell whether this is one of those situations. – matt May 17 '20 at 08:50
  • Thank you. It appears that Future starts as soon as it is created, even if nothing subscribes to it, so for me it's better to use Deffered + it allows .retry() in case of errors – Paul T. May 17 '20 at 10:47
  • Good, I’m glad we caught that. – matt May 17 '20 at 14:00