Skip to content

Commit 3029263

Browse files
authored
Add 'Effect.publisher' for bridging effects from Combine (#1958)
We are looking to deprecate TCA's dependence on Combine, _e.g._ the direct conformance of `Effect` to `Publisher`, as well as many Combine-centric APIs, but that doesn't mean we want to eliminate support for using Combine with TCA. Our current advice given by our soft deprecations is to iterate over `publisher.values`, but this is unavailable in iOS 13 and 14, so let's introduce a dedicated bridging mechanism, instead.
1 parent bb38461 commit 3029263

File tree

2 files changed

+37
-20
lines changed

2 files changed

+37
-20
lines changed

Sources/ComposableArchitecture/Documentation.docc/Extensions/Effect.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828

2929
- ``EffectPublisher/unimplemented(_:)``
3030

31+
### Combine integration
32+
33+
- ``EffectPublisher/publisher(_:)``
34+
3135
### SwiftUI integration
3236

3337
- ``EffectPublisher/animation(_:)``

Sources/ComposableArchitecture/Effects/Publisher.swift

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
import Combine
22

3+
extension EffectPublisher where Failure == Never {
4+
/// Creates an effect from a Combine publisher.
5+
///
6+
/// - Parameter createPublisher: The closure to execute when the effect is performed.
7+
/// - Returns: An effect wrapping a Combine publisher.
8+
public static func publisher<P: Publisher>(_ createPublisher: @escaping () -> P) -> Self
9+
where P.Output == Action, P.Failure == Never {
10+
Self(
11+
operation: .publisher(Deferred(createPublisher: createPublisher).eraseToAnyPublisher())
12+
)
13+
}
14+
}
15+
316
@available(iOS, deprecated: 9999.0)
417
@available(macOS, deprecated: 9999.0)
518
@available(tvOS, deprecated: 9999.0)
@@ -79,19 +92,19 @@ extension EffectPublisher {
7992
/// - Parameter publisher: A publisher.
8093
@available(
8194
iOS, deprecated: 9999.0,
82-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
95+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
8396
)
8497
@available(
8598
macOS, deprecated: 9999.0,
86-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
99+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
87100
)
88101
@available(
89102
tvOS, deprecated: 9999.0,
90-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
103+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
91104
)
92105
@available(
93106
watchOS, deprecated: 9999.0,
94-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
107+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
95108
)
96109
public init<P: Publisher>(_ publisher: P) where P.Output == Output, P.Failure == Failure {
97110
self.operation = .publisher(publisher.eraseToAnyPublisher())
@@ -367,19 +380,19 @@ extension Publisher {
367380
/// - Returns: An effect that wraps `self`.
368381
@available(
369382
iOS, deprecated: 9999.0,
370-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
383+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
371384
)
372385
@available(
373386
macOS, deprecated: 9999.0,
374-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
387+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
375388
)
376389
@available(
377390
tvOS, deprecated: 9999.0,
378-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
391+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
379392
)
380393
@available(
381394
watchOS, deprecated: 9999.0,
382-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
395+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
383396
)
384397
public func eraseToEffect() -> EffectPublisher<Output, Failure> {
385398
EffectPublisher(self)
@@ -402,19 +415,19 @@ extension Publisher {
402415
/// - Returns: An effect that wraps `self` after mapping `Output` values.
403416
@available(
404417
iOS, deprecated: 9999.0,
405-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
418+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
406419
)
407420
@available(
408421
macOS, deprecated: 9999.0,
409-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
422+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
410423
)
411424
@available(
412425
tvOS, deprecated: 9999.0,
413-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
426+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
414427
)
415428
@available(
416429
watchOS, deprecated: 9999.0,
417-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
430+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
418431
)
419432
public func eraseToEffect<T>(
420433
_ transform: @escaping (Output) -> T
@@ -447,19 +460,19 @@ extension Publisher {
447460
/// - Returns: An effect that wraps `self`.
448461
@available(
449462
iOS, deprecated: 9999.0,
450-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
463+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
451464
)
452465
@available(
453466
macOS, deprecated: 9999.0,
454-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
467+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
455468
)
456469
@available(
457470
tvOS, deprecated: 9999.0,
458-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
471+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
459472
)
460473
@available(
461474
watchOS, deprecated: 9999.0,
462-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
475+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
463476
)
464477
public func catchToEffect() -> EffectTask<Result<Output, Failure>> {
465478
self.catchToEffect { $0 }
@@ -482,19 +495,19 @@ extension Publisher {
482495
/// - Returns: An effect that wraps `self`.
483496
@available(
484497
iOS, deprecated: 9999.0,
485-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
498+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
486499
)
487500
@available(
488501
macOS, deprecated: 9999.0,
489-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
502+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
490503
)
491504
@available(
492505
tvOS, deprecated: 9999.0,
493-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
506+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
494507
)
495508
@available(
496509
watchOS, deprecated: 9999.0,
497-
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
510+
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
498511
)
499512
public func catchToEffect<T>(
500513
_ transform: @escaping (Result<Output, Failure>) -> T

0 commit comments

Comments
 (0)