Skip to content

Commit bf17531

Browse files
committed
Update docs
1 parent b103f79 commit bf17531

File tree

8 files changed

+56
-29
lines changed

8 files changed

+56
-29
lines changed

Examples/CaseStudies/SwiftUICaseStudies/02-Effects-WebSocket.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,14 @@ struct WebSocketClient {
206206
}
207207

208208
extension WebSocketClient: DependencyKey {
209-
static let liveValue: Self = {
209+
static var liveValue: Self {
210+
return Self(
211+
open: { await WebSocketActor.shared.open(id: $0, url: $1, protocols: $2) },
212+
receive: { try await WebSocketActor.shared.receive(id: $0) },
213+
send: { try await WebSocketActor.shared.send(id: $0, message: $1) },
214+
sendPing: { try await WebSocketActor.shared.sendPing(id: $0) }
215+
)
216+
210217
final actor WebSocketActor: GlobalActor {
211218
final class Delegate: NSObject, URLSessionWebSocketDelegate {
212219
var continuation: AsyncStream<Action>.Continuation?
@@ -305,14 +312,7 @@ extension WebSocketClient: DependencyKey {
305312
self.dependencies[id] = nil
306313
}
307314
}
308-
309-
return Self(
310-
open: { await WebSocketActor.shared.open(id: $0, url: $1, protocols: $2) },
311-
receive: { try await WebSocketActor.shared.receive(id: $0) },
312-
send: { try await WebSocketActor.shared.send(id: $0, message: $1) },
313-
sendPing: { try await WebSocketActor.shared.sendPing(id: $0) }
314-
)
315-
}()
315+
}
316316

317317
static let testValue = Self(
318318
open: XCTUnimplemented("\(Self.self).open", placeholder: AsyncStream.never),

Examples/SpeechRecognition/SpeechRecognition/SpeechClient/Client.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct SpeechClient {
1919
}
2020

2121
extension SpeechClient: TestDependencyKey {
22-
static let previewValue = {
22+
static var previewValue: Self {
2323
let isRecording = ActorIsolated(false)
2424

2525
return Self(
@@ -64,8 +64,8 @@ extension SpeechClient: TestDependencyKey {
6464
}
6565
}
6666
)
67-
}()
68-
67+
}
68+
6969
static let testValue = Self(
7070
finishTask: XCTUnimplemented("\(Self.self).finishTask"),
7171
requestAuthorization: XCTUnimplemented(

Examples/SpeechRecognition/SpeechRecognition/SpeechClient/Live.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import ComposableArchitecture
22
import Speech
33

44
extension SpeechClient: DependencyKey {
5-
static let liveValue = {
5+
static var liveValue: Self {
66
let speech = Speech()
77
return Self(
88
finishTask: {
@@ -20,7 +20,7 @@ extension SpeechClient: DependencyKey {
2020
return await speech.startTask(request: request)
2121
}
2222
)
23-
}()
23+
}
2424
}
2525

2626
private actor Speech {

Examples/SpeechRecognition/SpeechRecognition/SpeechRecognition.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,6 @@ struct SpeechRecognitionView_Previews: PreviewProvider {
152152
store: Store(
153153
initialState: SpeechRecognition.State(transcribedText: "Test test 123"),
154154
reducer: SpeechRecognition()
155-
.dependency(\.speechClient, .liveValue)
156155
)
157156
)
158157
}

Examples/VoiceMemos/VoiceMemos/AudioRecorderClient/AudioRecorderClient.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ struct AudioRecorderClient {
1111
}
1212

1313
extension AudioRecorderClient: TestDependencyKey {
14-
static let previewValue = {
14+
static var previewValue: Self {
1515
let isRecording = ActorIsolated(false)
1616
let currentTime = ActorIsolated(0.0)
1717

@@ -31,7 +31,7 @@ extension AudioRecorderClient: TestDependencyKey {
3131
await currentTime.setValue(0)
3232
}
3333
)
34-
}()
34+
}
3535

3636
static let testValue = Self(
3737
currentTime: XCTUnimplemented("\(Self.self).currentTime", placeholder: nil),

Examples/VoiceMemos/VoiceMemos/AudioRecorderClient/LiveAudioRecorderClient.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ import AVFoundation
22
import ComposableArchitecture // TODO: Should `UncheckedSendable` live in `Dependencies`?
33

44
extension AudioRecorderClient: DependencyKey {
5-
static let liveValue: Self = {
5+
static var liveValue: Self {
66
let audioRecorder = AudioRecorder()
77
return Self(
88
currentTime: { await audioRecorder.currentTime },
99
requestRecordPermission: { await AudioRecorder.requestPermission() },
1010
startRecording: { url in try await audioRecorder.start(url: url) },
1111
stopRecording: { await audioRecorder.stop() }
1212
)
13-
}()
13+
}
1414
}
1515

1616
private actor AudioRecorder {

Sources/ComposableArchitecture/Documentation.docc/Articles/DependencyManagement.md

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -439,16 +439,6 @@ extension AudioPlayerClient: DependencyKey {
439439
}
440440
```
441441

442-
> Tip: The live, preview and test values provided to the `DependencyKey` conformance should
443-
typically be `static let`'s, and never computed `static var`'s. If you need to perform some work
444-
to construct the value, then you can wrap it in a closure that is invoked immediately:
445-
>
446-
> ```swift
447-
> static let liveValue = {
448-
> //
449-
> }()
450-
> ```
451-
452442
If you design your dependencies in this way you can pick which dependency endpoints you need in your
453443
feature. For example, if you have a feature that needs an audio player to do its job, but it only
454444
needs the `play` endpoint, and doesn't need to loop, set volume or stop audio, then you can specify

Sources/Dependencies/DependencyKey.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,44 @@ import XCTestDynamicOverlay
1111
/// ``liveValue`` is accessed while your feature runs in a `TestStore` a test failure will be
1212
/// triggered.
1313
///
14+
/// To add a `UserClient` dependency that can fetch and save user values can be done like so:
15+
///
16+
/// ```swift
17+
/// // The user client dependency.
18+
/// struct UserClient {
19+
/// var fetchUser: (User.ID) async throws -> User
20+
/// var saveUser: (User) async throws -> Void
21+
/// }
22+
/// // Conform to DependencyKey to provide a live implementation of
23+
/// // the interface.
24+
/// extension UserClient: DependencyKey {
25+
/// static let liveValue = Self(
26+
/// fetchUser: { /* Make request to fetch user */ },
27+
/// saveUser: { /* Make request to save user */ }
28+
/// )
29+
/// }
30+
/// // Register the dependency within DependencyValues.
31+
/// extension DependencyValues {
32+
/// var userClient: UserClient {
33+
/// get { self[UserClient.self] }
34+
/// set { self[UserClient.self] = newValue }
35+
/// }
36+
/// }
37+
/// ```
38+
///
39+
/// When a dependency is first accessed its value is cached so that it will not be requested again.
40+
/// This means if your `liveValue` is implemented as a computed property instead of a `static let`,
41+
/// then it will only be called a single time:
42+
///
43+
/// ```swift
44+
/// extension UserClient: DependencyKey {
45+
/// static var liveValue: Self {
46+
/// // Only called once when dependency is first accessed.
47+
/// return Self(…)
48+
/// }
49+
/// }
50+
/// ```
51+
///
1452
/// `DependencyKey` inherits from ``TestDependencyKey``, which has two other overridable
1553
/// requirements: ``TestDependencyKey/testValue``, which should return a default value for the
1654
/// purpose of testing, and ``TestDependencyKey/previewValue-8u2sy``, which can return a default

0 commit comments

Comments
 (0)