Search code examples
swiftcombine

How to observe array's new values with combine?


If I have an array:

var arr = [0,1,2]

And a Combine publisher for it:

arr.publisher
    .sink { completion in print("Completed with \(completion)")
    } receiveValue: { val in
        print("Received value \(val)")
    }
arr.append(3)

Why does it finish right away with:

Received value 0
Received value 1
Received value 2
Completed with finished

How can I make Combine execute the code every time I append values to the array?


Solution

  • The publisher method of the array does exactly that - emits every element of the array and then completes, because the array at the time of calling the publisher has a finite number of elements.

    If you want to be notified every time the arrays changes (not just when something is appended to it, but on any change) then create a @Published var for the array and attach the observer to it:

    @Published var arr = [1,2,3]
    
    cancellable = $arr
        .sink { completion in print("Completed with \(completion)")
        } receiveValue: { val in
            print("Received value \(val)")
        }
    
    arr.append(4)
    

    The output will be:

    Received value [1, 2, 3]
    Received value [1, 2, 3, 4]
    
    

    But looks like what you are really looking for is listening to a stream of numbers emitted one at a time. Then define a @Published var of that type and listen to it. You'll get called every time the var changes:

    @Published var value = 1
    
    cancellable = $value
        .sink { completion in print("Completed with \(completion)")
        } receiveValue: { val in
            print("Received value \(val)")
        }
    
    value = 2
    value = 3
    value = 4
    

    The output will be:

    Received value 1
    Received value 2
    Received value 3
    Received value 4