skip to Main Content

Just getting into Combine, and for some reason I can’t get passthrough subjects to work. Even though I have copy-pasted examples from multiple different sources, they just won’t print anything. I have tried with Publishers and CurrentValueSubjects and they work fine, but with PassThroughSubjects; nope. Here’s an example that I have tried:

let mySubject = PassthroughSubject<String, Error>()

mySubject.sink(receiveCompletion: { completion in
        print("-- completion", completion)
    }, receiveValue: { value in
        print("-- value", value)
}).cancel()

mySubject.send("one")
mySubject.send("two")
mySubject.send("three")

This is run in viewDidLoad.
What am I doing wrong?

Like I said, I have tried Publishers and CurrentValueSubjects with success:

["one", "two", "three"].publisher
    .sink(receiveValue: { v in
        print("-- hello", v)
}).cancel()

let subject = CurrentValueSubject<String, Error>("Initial Value")

subject.send("Hello")

subject.sink(receiveCompletion: { c in
    print("-- completion", c)
}, receiveValue: { v in
    print("-- value", v)
}).cancel()

2

Answers


  1. Coming from rx I imagined .cancel() worked like .dispose(by:)

    No, cancel() is like dispose(), not disposed(by:) in rx. You should not cancel first, then send things to the subject. And unlike a CurrentValueSubject, it doesn’t remember the value you sent it, so you must send values to it after you sink, but before you cancel.

    Just like how you would use a DisposeBag in rx, you should do this with a Set<AnyCancellable> in Combine:

    var cancellables: Set<AnyCancellable> = []
    

    The Combine counterpart of disposed(by:) is store(in:):

    subject.sink(receiveCompletion: { c in
        print("-- completion", c)
    }, receiveValue: { v in
        print("-- value", v)
    }).store(in: &cancellables)
    
    subject.send("Hello")
    
    Login or Signup to reply.
  2. The warning that you are seeing that the subscription is unused is a hint to store the token returned by sink like so:

    let mySubject = PassthroughSubject<String, Error>()
    
    let cancellable = mySubject
        .sink(
            receiveCompletion: { completion in
                print("-- completion", completion)
            },
            receiveValue: { value in
                print("-- value", value)
            }
        )
    

    then when you call:

    mySubject.send("one")
    mySubject.send("two")
    mySubject.send("three")
    

    you will see this printed out:

    -- value one
    -- value two
    -- value three
    

    you can cancel the subscription if you are not longer interested in receiving updates:

    cancellable.cancel()
    

    or you can send a completion:

    mySubject.send(completion: .finished)
    

    and then you will see this printed out:

    -- completion finished
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search