2

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?

Stan
  • 77
  • 1
  • 7

1 Answers1

6

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


Vadim Dagman
  • 331
  • 1
  • 7
  • What if I want to subscribe to an array defined in UIKit, for example, UIStackView's arrangedSubviews array. I want it to publish each time the array elements change. I tried doing this with `publisher(for: \.arrangedSubviews)` on the stack view, but it's not working. Let me know if you want this as a separate question in Stack Overflow. – alobaili Jun 13 '22 at 11:30
  • 1
    You can only use that kind of publisher on key-value observable properties (KVO). `arrangedSubviews` is not a KVO property. – Vadim Dagman Jun 21 '22 at 02:33
  • Is there an easy way to identify if a property is KVO or not? Instead of manually trying it on a publisher and observing the effect? – alobaili Jun 21 '22 at 13:53
  • 2
    Unfortunately there is no easy way to tell in general. Sometimes Apple documentation states that a given property is KVO observable but it fails to say so for many that in fact are KVO observable. For one thing if a property is `readonly` (only has a getter) then it's almost certainly is not KVO observable, and the `arrangedSubviews` is a readonly property. – Vadim Dagman Jun 22 '22 at 00:49