Skip to content

Instantly share code, notes, and snippets.

@drumnkyle
Last active March 11, 2020 23:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drumnkyle/5a8a3fd4f92ec19f9d613fd02d40b795 to your computer and use it in GitHub Desktop.
Save drumnkyle/5a8a3fd4f92ec19f9d613fd02d40b795 to your computer and use it in GitHub Desktop.
Erasing Combine Subjects Property Wrapper
#if canImport(Combine)
import Combine
@propertyWrapper
/// Provides a property wrapper whose projected value is a `PassthroughSubject`, but
/// the wrapped value is just an `AnyPublisher`. This allows you to make a property with
/// availability declared for only iOS 13+ and hide the actual publisher.
public struct ErasedPassthroughSubject<Output, Failure: Error> {
private var value: Any?
@available(iOS 13.0, tvOS 13.0, OSX 10.15, *)
public var wrappedValue: AnyPublisher<Output, Failure> {
return passthroughSubject().eraseToAnyPublisher()
}
@available(iOS 13.0, tvOS 13.0, OSX 10.15, *)
public var projectedValue: PassthroughSubject<Output, Failure> {
return passthroughSubject()
}
/// Creates the underlying `PassthroughSubject` automatically.
public init() {
if #available(iOS 13.0, tvOS 13.0, OSX 10.15, *) {
self.value = PassthroughSubject<Output, Failure>()
} else {
self.value = nil
}
}
@available(iOS 13.0, tvOS 13.0, OSX 10.15, *)
private func passthroughSubject() -> PassthroughSubject<Output, Failure> {
return (value as? PassthroughSubject) ?? PassthroughSubject()
}
}
@propertyWrapper
/// Provides a property wrapper whose projected value is a `CurrentValueSubject`, but
/// the wrapped value is just an `AnyPublisher`. This allows you to make a property with
/// availability declared for only iOS 13+ and hide the actual publisher.
public struct ErasedCurrentValueSubject<Output, Failure: Error> {
private var value: Any?
private var firstValue: Output
@available(iOS 13.0, tvOS 13.0, OSX 10.15, *)
public var wrappedValue: AnyPublisher<Output, Failure> {
return currentValueSubject().eraseToAnyPublisher()
}
@available(iOS 13.0, tvOS 13.0, OSX 10.15, *)
public var projectedValue: CurrentValueSubject<Output, Failure> {
return currentValueSubject()
}
/// Initialize with a current value.
/// - Parameter currentValue: The current value to initialize the `CurrentValueSubject`
/// with.
public init(currentValue: Output) {
firstValue = currentValue
if #available(iOS 13.0, tvOS 13.0, OSX 10.15, *) {
self.value = CurrentValueSubject<Output, Failure>(currentValue)
} else {
self.value = nil
}
}
@available(iOS 13.0, tvOS 13.0, OSX 10.15, *)
private func currentValueSubject() -> CurrentValueSubject<Output, Failure> {
return (value as? CurrentValueSubject) ?? CurrentValueSubject(firstValue)
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment