William Hu
William Hu

Reputation: 16141

Swift Combine doesn't update value by sink

I want to achieve this: A class A, which has a property var c1: C and var b1: B, if the property of C changes, then the property of b1 should be updated.

Here is my code:

import UIKit
import Combine

struct B {
    var b = "b"
}

class C: ObservableObject {
    @Published var c: String = "c1"
}

class A: ObservableObject {
    var b1 = B()
    var cancellables = Set<AnyCancellable>()
    @Published var c1 = C()

    init() {

        $c1.sink {
            print("new value is \($0.c)") //Only print once
            self.b1.b = $0.c
        }.store(in: &cancellables)
    }

    func printMe() {
        print("b1.b: \(b1.b)")
        print("c1.c: \(c1.c)")
    }
}



let a = A()
a.c1.c = "c2"
a.printMe()


a.c1.c = "c3"
a.printMe()

The output is:

new value is c1
b1.b: c1
c1.c: c2
b1.b: c1
c1.c: c3

Every time the a.c1.c was updated I expected a.b1.b should be updated automatically by sink, not sure if anything I missed, the sink closure body just was called once.

Any suggestion? thanks!

Upvotes: 0

Views: 3411

Answers (1)

jrturton
jrturton

Reputation: 119242

With @Published var c1 = C() and $c1.sink you are observing changes to A's property c1. This assignment does not change, since it is a reference type, so the sink is only called on initialisation.

Updating the sink to:

c1.$c.sink {
    print("new value is \($0)") //Prints every time! 
        self.b1.b = $0
    }.store(in: &cancellables)

Gives the behaviour you're looking for. I don't think the c1 publisher will emit any values in this scenario, but it's not clear what behaviour you're looking for there so I haven't gone into it.

Upvotes: 2

Related Questions