Combine Publisher performs .sink action only once

Viewed 27

I have a ViewModel with following variable:
@Published var refreshed: Bool = false

Then, I use this variable in View on list's refresh like this:

List {
    [code...]
}
.refreshable {
    ratingsViewModel.refreshed = true
    ratingsViewModel.onRefresh()
}

My ratingsViewModel has it's function onRefresh which is fired on every view's refresh (as above):

func onRefresh() {
        myCurrentRatingsList
            .sink(receiveValue: { [weak self] ratingsList in
                print(self?.refreshed)
            })
            .store(in: &cancellableSet)
    }

myCurrentRatingsList is publisher created like this:

private lazy var myCurrentRatingsList: AnyPublisher<[RatingsListSection: [RatingsListRow]], Never> = {
        myCurrentRatingsRepository.ratingsList
            .share()
            .replaceError(with: [:])
            .eraseToAnyPublisher()
    }()

The problem is function onRefresh is executed also on ratingsViewModel init so ratingsViewModel.refreshed value is printed when ViewModel instance is created. When I use refreshable on list by pulling down the screen, nothing is printed (the animation works).
My question: is .sink only usable once? If yes, how can I replace it so that I can update value from my publisher many times

1 Answers

The problem with your code is, there's no reference for the sink that you created and so once the function execution is complete, the memory is flushed out and the sink doesn't exist anymore to trigger multiple times.

    private var mySink : AnyCancellable? // keep this variable as class member
    func onRefresh() {
        mySink = myCurrentRatingsList
            .sink(receiveValue: { [weak self] ratingsList in
                print(self?.refreshed)
            })
    }
Related