Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 586
Paul T. Avatar asked May 17 '20 03:05

Paul T.


People also ask

What is a publisher in combine?

At the heart of Combine is the Publisher protocol. This protocol defines the requirements for a type to be able to transmit a sequence of values over time to one or more subscribers. In other words, a publisher publishes or emits events that can include values of interest.

What does combine sink do?

sink(receiveCompletion:receiveValue:) takes two closures. The first closure executes when it receives Subscribers. Completion , which is an enumeration that indicates whether the publisher finished normally or failed with an error.

What is swift combine?

Overview. The Combine framework provides a declarative Swift API for processing values over time. These values can represent many kinds of asynchronous events. Combine declares publishers to expose values that can change over time, and subscribers to receive those values from the publishers.

What is just in combine?

Just is a publisher that creates an <Int, Never> type combination, provides a single value and then completes. 2. the closure provided to the . map() function takes in an <Int> and transforms it into a <String> . Since the failure type of <Never> is not changed, it is passed through.


1 Answers

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()
}
like image 95
Paul T. Avatar answered Oct 10 '22 13:10

Paul T.