Skip to content

Commit eb44c7e

Browse files
authored
Converge successive updates of an ObservableObject to a single update (#164)
1 parent 1ccf087 commit eb44c7e

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

Sources/Atoms/Atom/ObservableObjectAtom.swift

+5-2
Original file line numberDiff line numberDiff line change
@@ -70,19 +70,22 @@ public extension ObservableObjectAtom {
7070
AtomProducer { context in
7171
context.transaction(object)
7272
} manageValue: { object, context in
73+
var task: Task<Void, Never>?
7374
let cancellable = object
7475
.objectWillChange
7576
.sink { [weak object] _ in
7677
// Wait until the object's property is set, because `objectWillChange`
7778
// emits an event before the property is updated.
78-
Task { @MainActor in
79-
if !context.isTerminated, let object {
79+
task?.cancel()
80+
task = Task { @MainActor in
81+
if let object, !Task.isCancelled, !context.isTerminated {
8082
context.update(with: object)
8183
}
8284
}
8385
}
8486

8587
context.onTermination = {
88+
task?.cancel()
8689
cancellable.cancel()
8790
}
8891
}

Tests/AtomsTests/Atom/ObservableObjectAtomTests.swift

+40
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,44 @@ final class ObservableObjectAtomTests: XCTestCase {
116116
XCTAssertEqual(effect.updatedCount, 3)
117117
XCTAssertEqual(effect.releasedCount, 1)
118118
}
119+
120+
@MainActor
121+
func testUpdateMultipletimes() async {
122+
final class TestObject: ObservableObject {
123+
@Published
124+
var value0 = 0
125+
@Published
126+
var value1 = 0
127+
128+
func update() {
129+
value0 += 1
130+
value1 += 1
131+
}
132+
}
133+
134+
struct TestAtom: ObservableObjectAtom, Hashable {
135+
func object(context: Context) -> TestObject {
136+
TestObject()
137+
}
138+
}
139+
140+
let atom = TestAtom()
141+
let context = AtomTestContext()
142+
let object = context.watch(atom)
143+
var updatedCount = 0
144+
145+
context.onUpdate = {
146+
updatedCount += 1
147+
}
148+
149+
object.update()
150+
151+
await context.wait(for: atom) {
152+
$0.value0 == 1 && $0.value1 == 1
153+
}
154+
155+
XCTAssertEqual(updatedCount, 1)
156+
XCTAssertEqual(object.value0, 1)
157+
XCTAssertEqual(object.value1, 1)
158+
}
119159
}

0 commit comments

Comments
 (0)