Search code examples
swiftswiftuicombine

Swift Combine Publish Twice


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?

Solution

  • 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 "" ""