Hi @prathameshk, I highly recommend you do not use that publisher tool. The use of Task { … }
in withObservationTracking
in order to get the changed value has potential race conditions. This test shows the problem:
@Observable
class Model {
var count = 0
}
final class ObservablePublisherTests: XCTestCase {
func testBasics() async throws {
let model = Model()
let countPublisher = model.publisher(keyPath: \Model.count)
var values: [Int] = []
let cancellable = countPublisher.sink { int in
values.append(int)
}
let max = 10
for _ in 1...max {
model.count += 1
try await Task.sleep(for: .seconds(0.01))
}
XCTAssertEqual(values.count, max) // ✅
XCTAssertEqual(values, Array(1...max)) // ❌
_ = cancellable
}
}
This test does pass sometimes, but it will fail if you run it repeatedly, and you will get a failure like this:
XCTAssertEqual failed: ("[1, 2, 3, 4, 5, 6, 7, 7, 9, 10]") is not equal to ("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]")
This shows that the 8
value was not emitted and instead a stale 7
value took its place. This is due to the race condition of using the unstructured Task
.