Skip to content

Commit c52b053

Browse files
committed
- I changed the API because I like to use the word value in other parts of my code and I ended up using value.value and it made me sad.
- value -> raw - valueObservable -> observable - valueStream -> stream
1 parent e304d9a commit c52b053

14 files changed

+149
-146
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
All notable changes to AsyncObservable will be documented in this file.
44

5+
## [0.3.0] - 2025-03-08
6+
7+
### Changed
8+
- I changed the API because I like to use the word "value" in other parts of my code and I ended up using "value.value" and it made me sad.
9+
- value -> raw
10+
- valueObservable -> observable
11+
- valueStream -> stream
12+
513
## [0.2.1] - 2025-03-07
614

715
### Added

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ The API is probably stable. Let me know if the API should change, otherwise this
1010

1111
```swift
1212
// values
13-
asyncObservable.value
14-
asyncObservable.valueStream
15-
asyncObservable.valueObservable
13+
asyncObservable.raw
14+
asyncObservable.stream
15+
asyncObservable.observable
1616

1717
// updates
1818
asyncObservable.update(2)
@@ -37,17 +37,17 @@ actor Something {
3737
}
3838

3939
let something = Something()
40-
something.someProperty.value // "Hello, world!"
40+
something.someProperty.raw // "Hello, world!"
4141

42-
for await value in something.someProperty.valueStream {
42+
for await value in something.someProperty.stream {
4343
print(value) // hello world (then whatever the property is updated to)
4444
}
4545

4646

4747
struct SomethingView: View {
4848
let something: Something // Note: someProperty should be marked with @MainActor for this to work as is
4949
var body: some View {
50-
Text(something.someProperty.valueObservable) // hello world (then whatever the property is updated to)
50+
Text(something.someProperty.observable) // hello world (then whatever the property is updated to)
5151
}
5252
}
5353
```
@@ -59,7 +59,7 @@ The streams buffering policy defaults to `.unbounded`, so it will "gather" value
5959
```swift
6060
let someProperty = AsyncObservable(1)
6161

62-
let stream = someProperty.valueStream // already has 1
62+
let stream = someProperty.stream // already has 1
6363
someProperty.update { $0 + 1 } // 2
6464
someProperty.update { $0 + 1 } // 3
6565
someProperty.update { $0 + 1 } // 4
@@ -74,7 +74,7 @@ Canceling the task that the stream is running in will cancel the stream. So you
7474
```swift
7575
let someProperty = AsyncObservable(1)
7676

77-
let stream = someProperty.valueStream // already has 1
77+
let stream = someProperty.stream // already has 1
7878
let task = Task {
7979
for await value in stream {
8080
print(value) // 1, 2, 3
@@ -93,7 +93,7 @@ Streams are finalized as soon as you break out of the loop, so you can't reuse t
9393
```swift
9494
let someProperty = AsyncObservable(1)
9595

96-
let stream = someProperty.valueStream // already has 1
96+
let stream = someProperty.stream // already has 1
9797
// only print first value
9898
for await value in stream {
9999
print(value) // 1
@@ -106,7 +106,7 @@ for await value in stream {
106106
}
107107

108108
// do this ✅
109-
for await value in someProperty.valueStream {
109+
for await value in someProperty.stream {
110110

111111
}
112112
```

Sources/AsyncObservable/AsyncObservable.swift

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -71,22 +71,22 @@ open class AsyncObservable<T: Sendable>: AsyncObservableReadOnly, @unchecked Sen
7171
/// The observable state object for SwiftUI/UIKit integration.
7272
/// This property is accessed on the MainActor to ensure thread-safe UI updates.
7373
@MainActor
74-
public lazy var observable: State = {
75-
let observable = State(value: value, didSetValue: didUpdateFromObservable)
76-
return observable
74+
public lazy var observableState: State = {
75+
let observableState = State(value: raw, didSetValue: didUpdateFromObservable)
76+
return observableState
7777
}()
7878

7979
/// The current value accessible from the MainActor.
8080
/// This is a convenience property that provides direct access to the observable value.
8181
@MainActor
82-
public var valueObservable: T {
83-
observable.value
82+
public var observable: T {
83+
observableState.value
8484
}
8585

8686
/// An async stream of values that can be used with Swift concurrency.
8787
/// This property provides a convenient way to access the value stream without calling `stream()`.
88-
public var valueStream: StreamOf<T> {
89-
stream()
88+
public var stream: StreamOf<T> {
89+
streamOf()
9090
}
9191

9292
/// Storage for active stream continuations, keyed by UUID to allow multiple observers
@@ -95,13 +95,13 @@ open class AsyncObservable<T: Sendable>: AsyncObservableReadOnly, @unchecked Sen
9595

9696
/// The current value managed by this instance.
9797
/// Updates to this value are automatically propagated to all observers.
98-
private var _value: T
99-
public private(set) var value: T {
98+
private var _raw: T
99+
public private(set) var raw: T {
100100
get {
101-
serialQueue.sync { _value }
101+
serialQueue.sync { _raw }
102102
}
103103
set {
104-
serialQueue.sync { _value = newValue }
104+
serialQueue.sync { _raw = newValue }
105105
}
106106
}
107107
private var _shouldUpdateFromObservable = true
@@ -137,7 +137,7 @@ open class AsyncObservable<T: Sendable>: AsyncObservableReadOnly, @unchecked Sen
137137
}
138138
DispatchQueue.main.async {
139139
self.shouldUpdateFromObservable = false
140-
self.observable.value = value
140+
self.observableState.value = value
141141
self.shouldUpdateFromObservable = true
142142
}
143143
}
@@ -164,7 +164,7 @@ open class AsyncObservable<T: Sendable>: AsyncObservableReadOnly, @unchecked Sen
164164
serialQueue: DispatchQueue = DispatchQueue(label: "AsyncObservable")
165165
)
166166
{
167-
_value = initialValue
167+
_raw = initialValue
168168
self.bufferingPolicy = bufferingPolicy
169169
self.serialQueue = serialQueue
170170
}
@@ -189,7 +189,7 @@ open class AsyncObservable<T: Sendable>: AsyncObservableReadOnly, @unchecked Sen
189189
/// - notifyObservers: Whether to notify stream observers (default: true)
190190
/// - updateObservable: Whether to update the observable state (default: true)
191191
public func update(_ value: T, notifyObservers: Bool = true, updateObservable: Bool = true) {
192-
self.value = value
192+
self.raw = value
193193
updated(value, notifyObservers: notifyObservers, updateObservable: updateObservable)
194194
}
195195

@@ -202,7 +202,7 @@ open class AsyncObservable<T: Sendable>: AsyncObservableReadOnly, @unchecked Sen
202202
public func update(
203203
_ cb: @escaping (_ value: T) -> (T), notifyObservers: Bool = true, updateObservable: Bool = true
204204
) {
205-
let newValue = cb(value)
205+
let newValue = cb(raw)
206206
update(newValue, notifyObservers: notifyObservers, updateObservable: updateObservable)
207207
}
208208

@@ -217,9 +217,9 @@ open class AsyncObservable<T: Sendable>: AsyncObservableReadOnly, @unchecked Sen
217217
updateObservable: Bool = true
218218
) {
219219
serialQueue.sync {
220-
cb(&_value)
220+
cb(&_raw)
221221
}
222-
updated(value, notifyObservers: notifyObservers, updateObservable: updateObservable)
222+
updated(raw, notifyObservers: notifyObservers, updateObservable: updateObservable)
223223
}
224224

225225
/// Internal helper to manage stream continuations
@@ -237,7 +237,7 @@ open class AsyncObservable<T: Sendable>: AsyncObservableReadOnly, @unchecked Sen
237237
/// The stream immediately yields the current value and then yields all subsequent updates.
238238
///
239239
/// - Returns: A StreamOf<T> instance that can be used with async/await code
240-
private func stream() -> StreamOf<T> {
240+
private func streamOf() -> StreamOf<T> {
241241
let id = UUID()
242242
return StreamOf<T>(
243243
bufferingPolicy: bufferingPolicy,
@@ -248,7 +248,7 @@ open class AsyncObservable<T: Sendable>: AsyncObservableReadOnly, @unchecked Sen
248248
builder: { [weak self] continuation in
249249
guard let self else { return }
250250
self.setContinuation(id: id, continuation: continuation)
251-
continuation.yield(self.value)
251+
continuation.yield(self.raw)
252252
})
253253
}
254254
}

Sources/AsyncObservable/AsyncObservableReadOnly.swift

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,15 @@ public protocol AsyncObservableReadOnly<T>: Sendable {
99
/// The type of value being observed.
1010
associatedtype T: Sendable
1111

12-
/// The observable state object for SwiftUI/UIKit integration.
13-
/// This property is accessed on the MainActor to ensure thread-safe UI updates.
14-
@MainActor
15-
var observable: AsyncObservable<T>.State { get }
16-
1712
/// The current value accessible from the MainActor.
1813
/// This is a convenience property that provides direct access to the observable value.
1914
@MainActor
20-
var valueObservable: T { get }
15+
var observable: T { get }
2116

2217
/// An async stream of values that can be used with Swift concurrency.
2318
/// This property provides a convenient way to access the value stream.
24-
var valueStream: StreamOf<T> { get }
19+
var stream: StreamOf<T> { get }
2520

2621
/// The current value managed by this instance.
27-
var value: T { get }
22+
var raw: T { get }
2823
}

Tests/AsyncObservableTests/AdvancedBehaviorTests.swift

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ struct AsyncObservableAdvancedTests {
1212

1313
var receivedValues = [Int]()
1414

15-
let valueStream = observable.valueStream
15+
let stream = observable.stream
1616
let task = Task {
17-
for await value in valueStream {
17+
for await value in stream {
1818
receivedValues.append(value)
1919
if receivedValues.count >= 4 {
2020
break
@@ -33,7 +33,7 @@ struct AsyncObservableAdvancedTests {
3333

3434
// We should have received values in the correct sequence
3535
#expect(receivedValues == [0, 1, 2, 3])
36-
#expect(observable.value == 3)
36+
#expect(observable.raw == 3)
3737
}
3838

3939
@Test("Should handle custom buffering policies")
@@ -51,7 +51,7 @@ struct AsyncObservableAdvancedTests {
5151

5252
var unboundedValues = [Int]()
5353
let unboundedTask = Task {
54-
for await value in unboundedObservable.valueStream {
54+
for await value in unboundedObservable.stream {
5555
unboundedValues.append(value)
5656
if unboundedValues.count >= 10 {
5757
break // Important to break the loop
@@ -78,7 +78,7 @@ struct AsyncObservableAdvancedTests {
7878

7979
var noBufferValues = [Int]()
8080
let noBufferTask = Task {
81-
for await value in noBufferObservable.valueStream {
81+
for await value in noBufferObservable.stream {
8282
noBufferValues.append(value)
8383
break // Break immediately after first value
8484
}
@@ -98,11 +98,11 @@ struct AsyncObservableAdvancedTests {
9898
let observable = AsyncObservable(0)
9999

100100
var receivedValues = [Int]()
101-
let valueStream = observable.valueStream
101+
let stream = observable.stream
102102

103103
// Set up a task that will perform updates when specific values are observed
104104
let updateTask = Task {
105-
for await value in valueStream {
105+
for await value in stream {
106106
receivedValues.append(value)
107107

108108
// When we see value 2, trigger an update to 10
@@ -138,7 +138,7 @@ struct AsyncObservableAdvancedTests {
138138
#expect(receivedValues.contains(20))
139139

140140
// Final value should be 20
141-
#expect(observable.value == 20)
141+
#expect(observable.raw == 20)
142142
}
143143

144144
@Test("Should handle value cycling and detection of duplicate updates")
@@ -147,10 +147,10 @@ struct AsyncObservableAdvancedTests {
147147
let observable = AsyncObservable(0)
148148

149149
var receivedValues = [Int]()
150-
let valueStream = observable.valueStream
150+
let stream = observable.stream
151151

152152
// Consume initial value
153-
for await value in valueStream {
153+
for await value in stream {
154154
receivedValues.append(value)
155155
break
156156
}
@@ -161,7 +161,7 @@ struct AsyncObservableAdvancedTests {
161161
// Create a task to collect values
162162
let task = Task {
163163
var count = 0
164-
for await value in valueStream {
164+
for await value in stream {
165165
receivedValues.append(value)
166166
count += 1
167167
if count >= updatedValues.count {
@@ -198,21 +198,21 @@ struct AsyncObservableAdvancedTests {
198198
let observable = AsyncObservable(10)
199199

200200
// Get initial value
201-
let initialValue = observable.value
201+
let initialValue = observable.raw
202202
#expect(initialValue == 10)
203203

204204
// Verify we can update normally
205205
observable.update(30)
206-
#expect(observable.value == 30)
206+
#expect(observable.raw == 30)
207207

208208
// Test that value updates correctly through different methods
209209
observable.update(40)
210-
#expect(observable.value == 40)
210+
#expect(observable.raw == 40)
211211

212212
observable.update { current in current + 5 }
213-
#expect(observable.value == 45)
213+
#expect(observable.raw == 45)
214214

215215
observable.mutate { value in value += 5 }
216-
#expect(observable.value == 50)
216+
#expect(observable.raw == 50)
217217
}
218218
}

Tests/AsyncObservableTests/BasicTests.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ struct AsyncObservableBasicTests {
77

88
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
99
private func ensureValue<T: Equatable>(_ value: T, asyncObservable: AsyncObservable<T>) async {
10-
#expect(asyncObservable.value == value)
11-
await #expect(asyncObservable.valueObservable == value)
12-
for await value in asyncObservable.valueStream {
10+
#expect(asyncObservable.raw == value)
11+
await #expect(asyncObservable.observable == value)
12+
for await value in asyncObservable.stream {
1313
#expect(value == value)
1414
break
1515
}
@@ -30,10 +30,10 @@ struct AsyncObservableBasicTests {
3030
let observable = AsyncObservable(0)
3131
let newValue = 100
3232

33-
let valueStream = observable.valueStream
33+
let stream = observable.stream
3434
observable.update(newValue)
35-
await #expect(valueStream.first { _ in true } == 0)
36-
await #expect(valueStream.first { _ in true } == newValue)
35+
await #expect(stream.first { _ in true } == 0)
36+
await #expect(stream.first { _ in true } == newValue)
3737

3838
await ensureValue(newValue, asyncObservable: observable)
3939
}
@@ -43,12 +43,12 @@ struct AsyncObservableBasicTests {
4343
func testTransformUpdate() async {
4444
let observable = AsyncObservable(10)
4545

46-
let valueStream = observable.valueStream
46+
let stream = observable.stream
4747
observable.update { currentValue in
4848
return currentValue * 2
4949
}
50-
await #expect(valueStream.first { _ in true } == 10)
51-
await #expect(valueStream.first { _ in true } == 20)
50+
await #expect(stream.first { _ in true } == 10)
51+
await #expect(stream.first { _ in true } == 20)
5252
await ensureValue(20, asyncObservable: observable)
5353
}
5454

@@ -57,14 +57,14 @@ struct AsyncObservableBasicTests {
5757
func testMutateValue() async {
5858
let observable = AsyncObservable([1, 2, 3])
5959

60-
let valueStream = observable.valueStream
60+
let stream = observable.stream
6161
observable.mutate { value in
6262
value.append(4)
6363
}
64-
await #expect(valueStream.first { _ in true } == [1, 2, 3])
65-
await #expect(valueStream.first { _ in true } == [1, 2, 3, 4])
64+
await #expect(stream.first { _ in true } == [1, 2, 3])
65+
await #expect(stream.first { _ in true } == [1, 2, 3, 4])
6666

67-
#expect(observable.value == [1, 2, 3, 4])
68-
await #expect(observable.valueObservable == [1, 2, 3, 4])
67+
#expect(observable.raw == [1, 2, 3, 4])
68+
await #expect(observable.observable == [1, 2, 3, 4])
6969
}
7070
}

0 commit comments

Comments
 (0)