-
Notifications
You must be signed in to change notification settings - Fork 47
RF-9688 - Remove ReactiveSwift from Workflow public interface #360
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
72b41ed
to
bd84d2e
Compare
bd84d2e
to
13f4761
Compare
WorkflowUIReactiveSwift/Sources/WorkflowHostingController+OutputSignal.swift
Outdated
Show resolved
Hide resolved
Changed WorkflowHost and WorkflowHostingController to conform to WorkflowOutputPublisher. Added extension in WorkflowReactiveSwift to WorkflowOutputPublisher for output signal Removed unnecssary extensions on WorkflowHost and WorkflowHostingController
|
||
/// Represents the `Rendering` produced by the root workflow in the hierarchy. New `Rendering` values are produced | ||
/// as state transitions occur within the hierarchy. | ||
public let rendering: Property<WorkflowType.Rendering> | ||
public let rendering: ReadOnlyCurrentValueSubject<WorkflowType.Rendering, Never> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion:
@Published private(set) var rendering: WorkflowType.Rendering`
public var renderingPublisher: AnyPublisher<WorkflowType.Rendering, Never> {
$rendering.eraseToAnyPublisher()
}
private let rendering: CurrentValueSubject<Rendering, Never>
var renderingPublisher: AnyPublisher<Rendering, Never> {
rendering.eraseToAnyPublisher()
}
There's likely a few ways we could go about this without creating a custom subject. It's worth noting that @Published
is part of Combine and use-able anywhere as well. There's a bit of utility that comes with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AnyPublisher
isn't backward compatible with what we have now for rendering since you can't ask for the current value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops I read private
not private(set)
. rendering
has to be Public to keep clients working.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, the above with @Published
should make it essentially a public read only version of CurrentValueSubject
.
I sort of figured with the AnyPublisher
but figured I'd post it anyways just in case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From what I've gathered reading in the swift forums setting the value on CurrentValueSubject
is thread safe. I don't about @Published
. I'd have to check on that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To my knowledge, both CurrentValueSubject
does not guarentee thread safety nor is either documented to be so. You might gain some form of queued up items, but not necessarily the end results you're expecting.
https://www.cocoawithlove.com/blog/twenty-two-short-tests-of-combine-part-3.html#thread-safety
https://forums.swift.org/t/thread-safety-for-combine-publishers/29491/17
What you're probably looking at is this comment, but there's quite a few undocumented assumptions that come with this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was a while ago when we looked into CurrentValueSubject
. For sure it's not documented anywhere on thread safety (thanks Apple). Property
is what we are replacing (I sure wish we hadn't exposed this in the first place) we need something that supports the same semantics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After doing some testing it looks like @Published
and CurrentValueSubject
behave the same.
I do like not having to have an implementation detail exposed with the subject.
import ReactiveSwift | ||
import Workflow | ||
|
||
extension WorkflowOutputPublisher { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Is this just a duplicated version of
import Combine
import Foundation
import ReactiveSwift
extension Publisher {
/// Create a ReactiveSignal
public func toSignal() -> Signal<Output, Failure> {
Signal.unserialized { observer, lifetime in
let cancellable = self.sink(
receiveCompletion: { completion in
switch completion {
case .finished:
observer.sendCompleted()
case .failure(let error):
observer.send(error: error)
}
},
receiveValue: { value in
observer.send(value: value)
}
)
lifetime.observeEnded {
cancellable.cancel()
}
}
}
}
In our ReactiveSwiftCombineBridging
library?
Do we have a way of collapsing these if so - or is this more of a temporary transitional item needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't reference anything in register in Workflow. I don't think it would be worth adding a new public library just to share that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No it wouldn't, but we also need to be careful about fragmented/duplicated public utilities. If this was internal
and guaranteed to be 100% unique, I might be more ok with it. Both are public and almost 1-1 duplications meaning fragmentation and potential collisions at some point.
Is this just temporary though as ReactiveSwift is being removed from Workflow or is this a more or less long term duplicated utility?
For the consuming app, I do imagine outputPublisher.toSignal()
would work all the same leaving us with outputPublisher.toSignal()
and/or outputPublisher.output
essentially producing the same thing. I would imagine ouptuPublisher.output
could be internal to Workflow and outputPublisher.toSignal()
would be the application utility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a lot of usage of the current output
signal in the codebase so this keeps all those working by just adding an import statement.
I guess it's as temporary as we have consumers wanting a ReactiveSwift Signal. After we have the combine publisher in the consumers can definitely switch to using that and we could remove this extension.
The overall goal of this change is remove ReactiveSwift without breaking or having to change all the workflows in register.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool - totally get it given it's a migration path strategy.
This is a breaking change to Workflow that removes ReactiveSwift from the public interface of Workflow and Workflow UI.
There are 3 changes:
WorkflowHost
rendering
is now a Combine publisher that has avalue
property for the current rendering. In searching the register code base there were very few places we were using aSignal
/SignalProducer
from therendering
property. The plan would be to change those consumers to usesink
. Thevalue
property is the same so all references torendering.value
will work.WorkflowHost
output
has been renamed tooutputPublisher
. It is now a CombinePublisher
that can be used to subscribe to Workflow output. Per Andrew's suggestion I added a new protocolWorkflowOutputPubisher
that exposes theoutputPublisher
. Theoutput
property is used in a lot of places in register. To fix those places I added an extension onWorkflowOutputPubisher
in WorkflowReactiveSwift that re-exposesoutput
as aSignal
. All the places that useoutput
will just need to import WorkflowReactiveSwift and they will continue to work.WorkflowHostingController
in WorkflowUI now implementsWorkflowOutputPublisher
. Consumers usingoutput
will just need to import WorkflowReactiveSwift to continue to work.Note: Even though this removes ReactiveSwift as a dependency from the Workflow and WorkflowUI targets the Workflow Package has to continue to have ReactiveSwift as a dependency since it's used by WorkflowReactiveSwift. But because register uses bazel if you import Workflow/WorkflowUI in your module it does not import (directly or transitively) ReactiveSwift.
Checklist