Skip to content

Commit

Permalink
Add 'Effect.publisher' for bridging effects from Combine (#1958)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
stephencelis committed Mar 6, 2023
1 parent bb38461 commit 3029263
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@

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

### Combine integration

- ``EffectPublisher/publisher(_:)``

### SwiftUI integration

- ``EffectPublisher/animation(_:)``
Expand Down
53 changes: 33 additions & 20 deletions Sources/ComposableArchitecture/Effects/Publisher.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
import Combine

extension EffectPublisher where Failure == Never {
/// Creates an effect from a Combine publisher.
///
/// - Parameter createPublisher: The closure to execute when the effect is performed.
/// - Returns: An effect wrapping a Combine publisher.
public static func publisher<P: Publisher>(_ createPublisher: @escaping () -> P) -> Self
where P.Output == Action, P.Failure == Never {
Self(
operation: .publisher(Deferred(createPublisher: createPublisher).eraseToAnyPublisher())
)
}
}

@available(iOS, deprecated: 9999.0)
@available(macOS, deprecated: 9999.0)
@available(tvOS, deprecated: 9999.0)
Expand Down Expand Up @@ -79,19 +92,19 @@ extension EffectPublisher {
/// - Parameter publisher: A publisher.
@available(
iOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
macOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
tvOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
watchOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
public init<P: Publisher>(_ publisher: P) where P.Output == Output, P.Failure == Failure {
self.operation = .publisher(publisher.eraseToAnyPublisher())
Expand Down Expand Up @@ -367,19 +380,19 @@ extension Publisher {
/// - Returns: An effect that wraps `self`.
@available(
iOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
macOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
tvOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
watchOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
public func eraseToEffect() -> EffectPublisher<Output, Failure> {
EffectPublisher(self)
Expand All @@ -402,19 +415,19 @@ extension Publisher {
/// - Returns: An effect that wraps `self` after mapping `Output` values.
@available(
iOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
macOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
tvOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
watchOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
public func eraseToEffect<T>(
_ transform: @escaping (Output) -> T
Expand Down Expand Up @@ -447,19 +460,19 @@ extension Publisher {
/// - Returns: An effect that wraps `self`.
@available(
iOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
macOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
tvOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
watchOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
public func catchToEffect() -> EffectTask<Result<Output, Failure>> {
self.catchToEffect { $0 }
Expand All @@ -482,19 +495,19 @@ extension Publisher {
/// - Returns: An effect that wraps `self`.
@available(
iOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
macOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
tvOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
@available(
watchOS, deprecated: 9999.0,
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead."
message: "Iterate over 'Publisher.values' in an 'EffectTask.run', instead, or use 'EffectTask.publisher'."
)
public func catchToEffect<T>(
_ transform: @escaping (Result<Output, Failure>) -> T
Expand Down

0 comments on commit 3029263

Please sign in to comment.