Skip to content

Commit 10ba53d

Browse files
Add @SwiftUI.State.Shared and @SwiftUI.State.SharedReader (#110)
* wip * wip * wip * wip * wip * wip * wip * wip --------- Co-authored-by: Brandon Williams <[email protected]>
1 parent c2b1a88 commit 10ba53d

File tree

6 files changed

+400
-1
lines changed

6 files changed

+400
-1
lines changed

Examples/APIClientDemo/ContentView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ private let readMe = """
1111

1212
struct ContentView: View {
1313
@Shared(.appStorage("count")) var count = 0
14-
@SharedReader(.fact(nil)) var fact
14+
@State.SharedReader(.fact(nil)) var fact
1515
@State var isAboutPresented = false
1616

1717
var body: some View {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Dynamic Keys
2+
3+
Learn how to dynamically change the key that powers your shared state.
4+
5+
## Overview
6+
7+
Sharing uses the ``SharedKey`` protocol to express the functionality of loading, saving and
8+
subscribing to changes of an external storage system, such as user defaults, the file system
9+
and more. Often one needs to dynamically update the key so that the shared state can load
10+
different data. A common example of this is using `@SharedReader` to load data from a SQLite
11+
database, and needing to update the query with info specified by the user, such as a search string.
12+
13+
Learn about the techniques to do this below.
14+
15+
### Loading a new key
16+
17+
There are two ways to load a new key into `@Shared` and `@SharedReader`. If the change is due to
18+
the user changing something, such as a search string, you can use ``Shared/load(_:)``:
19+
20+
```swift
21+
.task(id: searchText) {
22+
do {
23+
try await $items.load(.search(searchText))
24+
} catch {
25+
// Handle error
26+
}
27+
}
28+
```
29+
30+
If the change is not due to user action, such as the first appearance of the view, then you can
31+
re-assign the projected value of the shared state directly:
32+
33+
```swift
34+
init() {
35+
$items = SharedReader(.search(searchText))
36+
}
37+
```
38+
39+
### SwiftUI views
40+
41+
There is one nuance to be aware of when using [`@Shared`](<doc:Shared>) and
42+
[`@SharedReader`](<doc:SharedReader>) directly in a SwiftUI view. When the view is recreated
43+
(which can happen many times and is an intentional design of SwiftUI), the corresponding
44+
`@Shared` and `@SharedReader` wrappers can also be created.
45+
46+
If you dynamically change the key of the property wrapper in the view, for example like this:
47+
48+
```swift
49+
$value.load(.newKey)
50+
// or...
51+
$value = Shared(.newKey)
52+
```
53+
54+
…then this key may be reset when the view is recreated. In order to prevent this you can use the
55+
version of `Shared` and `SharedReader` that works like `@State` in views:
56+
57+
```swift
58+
@State.Shared(.key) var value
59+
```
60+
61+
See ``SwiftUICore/State/Shared`` and ``SwiftUICore/State/SharedReader`` for more info.

Sources/Sharing/Documentation.docc/Articles/Gotchas.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,28 @@ extension TodosFeature: Codable {
6565
}
6666
}
6767
```
68+
69+
#### SwiftUI Views
70+
71+
There is one nuance to be aware of when using [`@Shared`](<doc:Shared>) and
72+
[`@SharedReader`](<doc:SharedReader>) directly in a SwiftUI view. When the view is recreated
73+
(which can happen many times and is an intentional design of SwiftUI), the corresponding
74+
`@Shared` and `@SharedReader` wrappers can also be created.
75+
76+
If you dynamically change the key of the property wrapper in the view, for example like this:
77+
78+
```swift
79+
$value.load(.newKey)
80+
// or…
81+
$value = Shared(.newKey)
82+
```
83+
84+
…then this key may be reset when the view is recreated. In order to prevent this you can use the
85+
version of `Shared` and `SharedReader` that works like `@State` in views:
86+
87+
```swift
88+
@State.Shared(.key) var value
89+
```
90+
91+
See ``SwiftUICore/State/Shared`` and ``SwiftUICore/State/SharedReader`` for more info, as well
92+
as the article <doc:DynamicKeys>.

Sources/Sharing/Documentation.docc/Articles/ObservingChanges.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,29 @@ struct CounterView: View {
4646
In each of these cases the view will automatically re-compute its body when the shared state
4747
changes.
4848

49+
> Important:
50+
> There is one nuance to be aware of when using [`@Shared`](<doc:Shared>) and
51+
> [`@SharedReader`](<doc:SharedReader>) directly in a SwiftUI view. When the view is recreated
52+
> (which can happen many times and is an intentional design of SwiftUI), the corresponding
53+
> `@Shared` and `@SharedReader` wrappers can also be created.
54+
>
55+
> If you dynamically change the key of the property wrapper in the view, for example like this:
56+
>
57+
> ```swift
58+
> $value.load(.newKey)
59+
> // or…
60+
> $value = Shared(.newKey)
61+
> ```
62+
>
63+
> then this key may be reset when the view is recreated. In order to prevent this you can use the
64+
> version of `Shared` and `SharedReader` that works like `@State` in views:
65+
>
66+
> ```swift
67+
> @State.Shared(.key) var value
68+
> ```
69+
>
70+
> See ``SwiftUICore/State/Shared`` and ``SwiftUICore/State/SharedReader`` for more info.
71+
4972
## Publisher of values
5073
5174
It is possible to get a Combine publisher of changes in a piece of shared state. Every `Shared`

Sources/Sharing/Documentation.docc/Sharing.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ complex problems with `@Shared`. Check out [this][examples-dir] directory to see
165165
- <doc:PersistenceStrategies>
166166
- <doc:MutatingSharedState>
167167
- <doc:ObservingChanges>
168+
- <doc:DynamicKeys>
168169
- <doc:DerivingSharedState>
169170
- <doc:TypeSafeKeys>
170171
- <doc:InitializationRules>

0 commit comments

Comments
 (0)