You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -124,6 +125,14 @@ GRDB adheres to [Semantic Versioning](https://semver.org/), with one exception:
124
125
125
126
---
126
127
128
+
## 6.27.0
129
+
130
+
Released April 21, 2024
131
+
132
+
- **Fixed**: [#1533](https://github.com/groue/GRDB.swift/pull/1533) by [@groue](https://github.com/groue): Fix a bug in Decodable support
133
+
- **Documentation Update**: [#1534](https://github.com/groue/GRDB.swift/pull/1534) The [Single-Row Tables](Documentation/SingleRowTables.md) guide was updated with guidance about default configuration values.
134
+
- **Documentation Update**: [#1535](https://github.com/groue/GRDB.swift/pull/1535) The [ValueObservation Scheduling](https://swiftpackageindex.com/groue/grdb.swift/documentation/grdb/valueobservation#ValueObservation-Scheduling) documentation chapter explains the default behavior of `ValueObservation` fetches, and explains how to make sure they are never performed on the main thread.
Copy file name to clipboardExpand all lines: Documentation/DemoApps/GRDBAsyncDemo/README.md
+2-1Lines changed: 2 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -13,8 +13,9 @@ The topics covered in this demo are:
13
13
14
14
- How to setup a database in an iOS app.
15
15
- How to define a simple [Codable Record](../../../README.md#codable-records).
16
-
- How to track database changes and animate a SwiftUI List with an async sequence built from [ValueObservation](https://swiftpackageindex.com/groue/grdb.swift/documentation/grdb/valueobservation).
16
+
- How to track database changes and animate a SwiftUI List with [ValueObservation](https://swiftpackageindex.com/groue/grdb.swift/documentation/grdb/valueobservation) Combine publishers.
17
17
- How to apply the recommendations of [Recommended Practices for Designing Record Types](https://swiftpackageindex.com/groue/grdb.swift/documentation/grdb/recordrecommendedpractices).
18
+
- How to perform `async` database accesses.
18
19
- How to feed SwiftUI previews with a transient database.
Copy file name to clipboardExpand all lines: GRDB/Documentation.docc/Extension/ValueObservation.md
+39-8Lines changed: 39 additions & 8 deletions
Original file line number
Diff line number
Diff line change
@@ -80,6 +80,8 @@ By default, `ValueObservation` notifies a fresh value whenever any component of
80
80
81
81
By default, `ValueObservation` notifies the initial value, as well as eventual changes and errors, on the main dispatch queue, asynchronously. This can be configured: see <doc:ValueObservation#ValueObservation-Scheduling>.
82
82
83
+
By default, `ValueObservation` fetches a fresh value immediately after a change is committed in the database. In particular, modifying the database on the main thread triggers a fetch on the main thread as well. This behavior can be configured: see <doc:ValueObservation#ValueObservation-Scheduling>.
84
+
83
85
`ValueObservation` may coalesce subsequent changes into a single notification.
84
86
85
87
`ValueObservation` may notify consecutive identical values. You can filter out the undesired duplicates with the ``removeDuplicates()`` method.
@@ -117,16 +119,45 @@ It is very useful in graphic applications, because you can configure views right
117
119
The `immediate` scheduling requires that the observation starts from the main dispatch queue (a fatal error is raised otherwise):
118
120
119
121
```swift
120
-
let cancellable = observation.start(in: dbQueue, scheduling: .immediate) { error in
121
-
// Called on the main dispatch queue
122
-
} onChange: { value in
123
-
// Called on the main dispatch queue
124
-
print("Fresh value", value)
125
-
}
122
+
// Immediate scheduling notifies
123
+
// the initial value right on subscription.
124
+
let cancellable = observation
125
+
.start(in: dbQueue, scheduling: .immediate) { error in
126
+
// Called on the main dispatch queue
127
+
} onChange: { value in
128
+
// Called on the main dispatch queue
129
+
print("Fresh value", value)
130
+
}
126
131
// <- Here "Fresh value" has already been printed.
127
132
```
128
133
129
-
The other built-in scheduler ``ValueObservationScheduler/async(onQueue:)`` asynchronously schedules values and errors on the dispatch queue of your choice.
134
+
The other built-in scheduler ``ValueObservationScheduler/async(onQueue:)`` asynchronously schedules values and errors on the dispatch queue of your choice. Make sure you provide a serial queue, because a concurrent one such as `DispachQueue.global(qos: .default)` would mess with the ordering of fresh value notifications:
135
+
136
+
```swift
137
+
// Async scheduling notifies all values
138
+
// on the specified dispatch queue.
139
+
let myQueue: DispatchQueue
140
+
let cancellable = observation
141
+
.start(in: dbQueue, scheduling: .async(myQueue)) { error in
142
+
// Called asynchronously on myQueue
143
+
} onChange: { value in
144
+
// Called asynchronously on myQueue
145
+
print("Fresh value", value)
146
+
}
147
+
```
148
+
149
+
As described above, the `scheduling` argument controls the execution of the change and error callbacks. You also have some control on the execution of the database fetch:
150
+
151
+
- With the `.immediate` scheduling, the initial fetch is always performed synchronously, on the main thread, when the observation starts, so that the initial value can be notified immediately.
152
+
153
+
- With the default `.async` scheduling, the initial fetch is always performed asynchronouly. It never blocks the main thread.
154
+
155
+
- By default, fresh values are fetched immediately after the database was changed. In particular, modifying the database on the main thread triggers a fetch on the main thread as well.
156
+
157
+
To change this behavior, and guarantee that fresh values are never fetched from the main thread, you need a ``DatabasePool`` and an optimized observation created with the ``tracking(regions:fetch:)`` or ``trackingConstantRegion(_:)`` methods. Make sure you read the documentation of those methods, or you might write an observation that misses some database changes.
158
+
159
+
It is possible to use a ``DatabasePool`` in the application, and an in-memory ``DatabaseQueue`` in tests and Xcode previews, with the common protocol ``DatabaseWriter``.
160
+
130
161
131
162
## ValueObservation Sharing
132
163
@@ -237,7 +268,7 @@ When needed, you can help GRDB optimize observations and reduce database content
237
268
>
238
269
> The `map` operator performs its job without blocking database accesses, and without blocking the main thread.
239
270
240
-
> Tip: When the observation tracks a constant database region, create an optimized observation with the ``trackingConstantRegion(_:)`` method. See the documentation of this method for more information about what constitutes a "constant region", and the nature of the optimization.
271
+
> Tip: When the observation tracks a constant database region, create an optimized observation with the ``tracking(regions:fetch:)`` or ``trackingConstantRegion(_:)`` methods. Make sure you read the documentation of those methods, or you might write an observation that misses some database changes.
241
272
242
273
**Truncating WAL checkpoints impact ValueObservation.** Such checkpoints are performed with ``Database/checkpoint(_:on:)`` or [`PRAGMA wal_checkpoint`](https://www.sqlite.org/pragma.html#pragma_wal_checkpoint). When an observation is started on a ``DatabasePool``, from a database that has a missing or empty [wal file](https://www.sqlite.org/tempfiles.html#write_ahead_log_wal_files), the observation will always notify two values when it starts, even if the database content is not changed. This is a consequence of the impossibility to create the [wal snapshot](https://www.sqlite.org/c3ref/snapshot_get.html) needed for detecting that no changes were performed during the observation startup. If your application performs truncating checkpoints, you will avoid this behavior if you recreate a non-empty wal file before starting observations. To do so, perform any kind of no-op transaction (such a creating and dropping a dummy table).
0 commit comments