Search code examples
iosclosuresswiftuicombinepublisher

Combine: Convert Closure into Publisher


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.


Solution

  • 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()
    }