Home > Software engineering >  Swift Combine sink called once at setup?
Swift Combine sink called once at setup?

Time:05-26

I am setting up a sink like so:

    name.publisher
        .removeDuplicates()
        .receive(on: RunLoop.main)
        .sink { [weak self] config in
            guard let self = self else { return }

            // this closure gets called right away at setup even though the @Published property `name` was already setup and did not change
            
        }.store(in: &subscribers)

The property is declared like so in an observable object:

 @Published var name:String = ""

So, I'm obviously missing something here. Why is sink called once at setup even though name did not change? I can avoid this behavior by using the dropFirst() operator but, I'd like to understand why the closure is always called once immediately after setup?

Why is that?

CodePudding user response:

Here's a playground that uses debugPrint to show you what you get from name.publisher:

import UIKit
import Combine

//Holds the score
class ViewModel : ObservableObject {
    @Published var name = "0"
}

let viewModel = ViewModel()
debugPrint(viewModel.name.publisher)

What you get is

Combine.Publishers.Sequence<Swift.String, Swift.Never>(sequence: "0")

So you get a sequence publisher that has a single item, "0". It will publish that value once and the sequence will end. Each time a subscriber attaches to that sequence it will get all the items in the sequence (there's only one) and the end.

This is probably not what you want.

Instead I think you want to use $name to access the published property:

import UIKit
import Combine

//Holds the score
class ViewModel : ObservableObject {
    @Published var name = "0"
}

let viewModel = ViewModel()
let subscription = viewModel.$name.sink { print($0) }
viewModel.name = "Alex"

When you subscribe to the published property you will still get a posted event that is the current value of the property. However, by using $name you are attaching to a stream that will send you the current value on subscription AND each subsequent value.

  • Related