0

I use Combine to track changes in the View Model and react to these changes in the View in the UIKit Application. The thing is that every time the change occurs sink is getting called one more time. I store subscriptions in the Set() and basically sink as called as many times as there are cancellables. If I remove and add items to the cart 5 times the sink would be called 10 times. Is this correct behavior or I'm doing something wrong?

My View Model Protocol:

protocol CartTrackable {
    var addedToCart: Bool { get set }
    var addedToCartPublisher: Published<Bool>.Publisher { get }
}

My View Model:

final class CartViewModel: ObservableObject, CartTrackable {
    @Published var addedToCart = false
    var addedToCartPublisher: Published<Bool>.Publisher { $addedToCart }

    func addToCart() {
        addedToCart = true
    }
    
    func removeFromCart() {
        addedToCart = false
    }
}

And here is the relevant code in my View:

 private var cancellables = Set<AnyCancellable>()

 func setObserver() {
        viewModel?.addedToCartPublisher
            .dropFirst()
            .receive(on: RunLoop.main)
            .sink { [weak self] cartStatus in
                self?.addToCartButton.showAnimation(for: cartStatus) 
            }
            .store(in: &cancellables)
    }

Declaring cancellable as one object helps - .sink is always called only once, but I keep track of several things, and having separate cancellables for them is just a lot of repeated code. Would love to hear your opinions! Cheers!

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
Roma Kavinskyi
  • 268
  • 4
  • 12
  • 3
    When are you calling `setObserver()`? – jrturton Sep 22 '22 at 10:55
  • When View Model is set: ```var viewModel: CartTrackable? { didSet { setObserver() } } ``` – Roma Kavinskyi Sep 22 '22 at 11:14
  • 2
    Is the view model setter perhaps multiple times? Point is, it looks like you've subscribed multiple times. Add a break point or log to `setObserver` to verify this and maybe guard against it. – DarkDust Sep 22 '22 at 11:16
  • You are right. The setter is called for no reason after `removeFromCart` is called. It's quite odd as the method where I assign value to the `viewModel` is not called. – Roma Kavinskyi Sep 22 '22 at 11:28
  • A system method called `modify` is called on view model automatically after I updated `@Published` causing the setter to fire. Thanks for help guys! – Roma Kavinskyi Sep 22 '22 at 11:58

0 Answers0