AsyncPublisher of KeyValueObservingPublisher doesn't work

Hi, I'm trying to use async/await for KVO and it seems something is broken. For some reason, it doesn't go inside for in body when I'm changing the observed property.

import Foundation
import PlaygroundSupport

class TestObj: NSObject {
  @objc dynamic var count = 0
}

let obj = TestObj()
Task {
  for await value in obj.publisher(for: \.count).values {
    print(value)
  }
}
Task.detached {
  try? await Task.sleep(for: .microseconds(100))
  obj.count += 1
}
Task.detached {
  try? await Task.sleep(for: .microseconds(200))
  obj.count += 1
}
PlaygroundPage.current.needsIndefiniteExecution = true

Expected result: 0, 1, 2

Actual result: 0

Does anyone know what is wrong here?

Post not yet marked as solved Up vote post of sviat_sem Down vote post of sviat_sem
1.9k views

Replies

I'm running into this same problem when trying to observe values from the KVO-compliant timeControlStatus property on AVPlayer:

    init() {
        self.player = AVPlayer()
        Task { [weak self] in
            guard let self else { return }
            // Observe changes to timeControlStatus using Combine on the AVPlayer
            for await newValue in player.publisher(for: \.timeControlStatus).values {
                 isPlaying = newValue == .playing // this only gets called for the initial value and never again, the loop does not exit
            }
        }
    }

This appears to be a bug in NSObject.KeyValueObservingPublisher. It's triggered because the values property only sends an initial Demand of .max(1) when it subscribes to the KVO publisher.

Forcing a larger Demand works around the problem. We can use the handleEvents operator to send unlimited demand to the KVO publisher:

Task {
    for await value in obj
        .publisher(for: \.count)
        .handleEvents(receiveSubscription: { $0.request(.unlimited) })
        .values
    {
        print("async: \(value)")
    }
}
  • This solution doesn’t seem to work: it prevents the code from getting also the first value.

Add a Comment