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()
CodePudding user response:
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
CodePudding user response:
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")