Skip to content

Commit

Permalink
Converge successive updates of an ObservableObject to a single update (
Browse files Browse the repository at this point in the history
  • Loading branch information
ra1028 authored Jan 22, 2025
1 parent 1ccf087 commit eb44c7e
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 2 deletions.
7 changes: 5 additions & 2 deletions Sources/Atoms/Atom/ObservableObjectAtom.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,22 @@ public extension ObservableObjectAtom {
AtomProducer { context in
context.transaction(object)
} manageValue: { object, context in
var task: Task<Void, Never>?
let cancellable = object
.objectWillChange
.sink { [weak object] _ in
// Wait until the object's property is set, because `objectWillChange`
// emits an event before the property is updated.
Task { @MainActor in
if !context.isTerminated, let object {
task?.cancel()
task = Task { @MainActor in
if let object, !Task.isCancelled, !context.isTerminated {
context.update(with: object)
}
}
}

context.onTermination = {
task?.cancel()
cancellable.cancel()
}
}
Expand Down
40 changes: 40 additions & 0 deletions Tests/AtomsTests/Atom/ObservableObjectAtomTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,44 @@ final class ObservableObjectAtomTests: XCTestCase {
XCTAssertEqual(effect.updatedCount, 3)
XCTAssertEqual(effect.releasedCount, 1)
}

@MainActor
func testUpdateMultipletimes() async {
final class TestObject: ObservableObject {
@Published
var value0 = 0
@Published
var value1 = 0

func update() {
value0 += 1
value1 += 1
}
}

struct TestAtom: ObservableObjectAtom, Hashable {
func object(context: Context) -> TestObject {
TestObject()
}
}

let atom = TestAtom()
let context = AtomTestContext()
let object = context.watch(atom)
var updatedCount = 0

context.onUpdate = {
updatedCount += 1
}

object.update()

await context.wait(for: atom) {
$0.value0 == 1 && $0.value1 == 1
}

XCTAssertEqual(updatedCount, 1)
XCTAssertEqual(object.value0, 1)
XCTAssertEqual(object.value1, 1)
}
}

0 comments on commit eb44c7e

Please sign in to comment.