Combine: Convert Closure into Publisher
Asked Answered
T

1

9

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.

Titration answered 17/5, 2020 at 3:23 Comment(3)
Just wrap it in a Future. I just spent the day doing this very thing! See apeth.com/UnderstandingCombine/publishers/publishersfuture.htmlModernity
Thank you! Could you post your answer? I'll mark it as a correct, so it will help anybody in future 🙂Titration
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!Modernity
T
20

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()
}
Titration answered 17/5, 2020 at 8:18 Comment(3)
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.Modernity
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 errorsTitration
Good, I’m glad we caught that.Modernity

© 2022 - 2024 — McMap. All rights reserved.