15

I am learning Swift Combine now, found quite easy video tutorial, however for some reason I get error when I try to use my enum in PassthroughSubject<Int, WeatherError>()

Check this code:

import Combine 

enum WeatherError: Error {
   case thingsJustHappen
   
}
let weatherPublisher = PassthroughSubject<Int, WeatherError>()


let subscriber = weatherPublisher
   .filter {$0 > 10}
   .sink { value in
       print("\(value)")
   }

weatherPublisher.send(10)
weatherPublisher.send(30)

".filter" is highlighted and the error is:

Referencing instance method 'sink(receiveValue:)' on 'Publisher' 
requires the types 'Publishers.Filter<PassthroughSubject<Int, WeatherError>>.Failure' 
(aka 'WeatherError') and 'Never' be equivalent

Surprisingly this code works in the video tutorial. How can I make my WeatherError and Never to be equivalent???

Piotr979
  • 199
  • 1
  • 2
  • 10

3 Answers3

43

You need to provide both handlers, the completion one, and the value one:

let subscriber = weatherPublisher
    .filter { $0 > 10 }
    .sink(receiveCompletion: { _ in }, receiveValue: { value in
       print("\(value)")
    })

This is needed because the single-argument sink, is available only for publishers that can never fail:

extension Publisher where Self.Failure == Never {
    /// ... many lines of documentation omitted
    public func sink(receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable
}
Cristik
  • 30,989
  • 25
  • 91
  • 127
  • 1
    Thanks for that, I just simply followed the tutorial which is a bit old (July 2019). I was just thinking If it may be the reason why is not working for me. I need to read more about sink and receiveCompletion/receiveValue. Thanks again Cristik. – Piotr979 Nov 15 '20 at 15:19
  • 5
    @Piotr979, yeah, outdated tutorials are sometimes worse than no tutorials at all :) – Cristik Nov 15 '20 at 15:20
  • Makes no sense but works! – Arbitur Dec 28 '22 at 01:38
  • Is there an easy way to convert the publisher into one which cannot fail? – aehlke Jan 04 '23 at 17:22
  • 1
    @aehlke see https://stackoverflow.com/questions/58227096/set-a-given-publishers-failure-type-to-never-in-combine – Cristik Apr 02 '23 at 12:52
1

It will work if you change the type to Never:

let weatherPublisher = PassthroughSubject<Int, Never>()

Or create a new Published variable:

@Published var weather = 0

let weatherPublisher = PassthroughSubject<Int, WeatherError>()

let weatherSubscriber = weather
   .filter { $0 > 10 }
   .sink { print($0) }

let subscriber = weatherPublisher
   .sink { [weak self] value in
       self?.weather = value
   }
Faruuq
  • 13
  • 3
-1

in Xcode 13 & iOS 15.4 this code needed brackets to compile.

extension Publisher where Self.Failure ==  Never {
    // because the publisher can NEVER FAIL - by design!
    public  func sink(receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable {  }
}
David
  • 141
  • 2
  • 12
  • Is this a reply to my answer? If yes, note that the code snippet was extracted from the Combine interface, so it's expected to contain only the declarations, not the implementations. – Cristik Apr 30 '22 at 11:17