Swift Combine Publish Twice

Viewed 946
class ObservableFormViewModel: ObservableObject {
  @Published var isSubmitAllowed: Bool = true
  @Published var username: String = ""
  @Published var password: String = ""
  var somethingElse: Int = 10
}

var form = ObservableFormViewModel()

let formSubscription = form.$isSubmitAllowed.sink { _ in
    print("Form changed: \(form.isSubmitAllowed) \"\(form.username)\" \"\(form.password)\"")
}


form.isSubmitAllowed = false
form.isSubmitAllowed = false
form.isSubmitAllowed = false

The output is:

Form changed: true "" ""
Form changed: true "" ""
Form changed: false "" ""
Form changed: false "" ""

My question is:

  • why true output comes 2 while false only 2?
  • any better way to remove duplicate?
1 Answers

why true output comes 2 while false only 2?

The first output is run when you create formSubscription. The next three are triggered by your consecutive form.isSubmitAllowed = false statements.

Note that you change form.isSubmitAllowed three times to false and in output it occurs only two times:

form.isSubmitAllowed = false
form.isSubmitAllowed = false
form.isSubmitAllowed = false

// Form changed: true "" ""
Form changed: true "" ""
Form changed: false "" ""
Form changed: false "" ""

This is because you're not printing the changed value but the old one.

Try this instead:

let formSubscription = form.$isSubmitAllowed.sink { isSubmitAllowed in
    print("Form changed: \(isSubmitAllowed) \"\(form.username)\" \"\(form.password)\"")
}

This prints:

// Form changed: true "" ""
Form changed: false "" ""
Form changed: false "" ""
Form changed: false "" ""

If you want to remove duplicates just use removeDuplicates:

let formSubscription = form.$isSubmitAllowed.removeDuplicates().sink { value in
    print("Form changed: \(value) \"\(form.username)\" \"\(form.password)\"")
}

form.isSubmitAllowed = false
form.isSubmitAllowed = false
form.isSubmitAllowed = false

This prints:

Form changed: true "" ""
Form changed: false "" ""
Related