- Notifications
You must be signed in to change notification settings - Fork46
RF-9688 - [refactor]: 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 ourterms of service andprivacy 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?
Uh oh!
There was an error while loading.Please reload this page.
Conversation
bd84d2e to13f4761CompareWorkflowUIReactiveSwift/Sources/WorkflowHostingController+OutputSignal.swiftShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
WorkflowReactiveSwift/Sources/WorkflowOutputPublisher+OutputSignal.swift OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
f7e5fc3 to59bcc8bCompareWorkflow/Sources/WorkflowHost.swift Outdated
| publicprotocolWorkflowOutputPublisher{ | ||
| associatedtypeOutput | ||
| varoutputPublisher:AnyPublisher<Output,Never>{get} | ||
| } |
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.
is this protocol necessary? what's the benefit over just extending the concrete type directly?
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 allows us to add the output signal on bothWorkflowHost andWorkflowHostingController by just extending the protocol in WorkflowReactiveSwift. This was a suggestion in Andrew's feedback.
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.
ah gotcha (sorry i missed the existing convo). so the tradeoff here is adding a 'public' protocol to which we really only want 2 specific things to conform so that we don't need to makeWorkflow orWorkflowUI depend onReactiveSwift – is that right? mostly out of curiosity – is it possible to define the protocol withpackage visibility? that seems like it might be a slightly more accurate definition (assuming it works and integrates successfully into the monorepo).
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.
Before I had extensions onWorkflowHost andWorkflowHostingController which required a new module just to put the extension onWorkflowHostingController since I could not put it inWorkflowReactiveSwift since it does not know aboutWorkflowUI. Andrew's idea was use a protocol and drop the extension inWorkflowReactiveSwift so we don't need to have an additional module and the reactive swift stuff stays inWorkflowReactiveSwift.
I can look into thepackage visibility to see if that is possible.
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.
If I make the protocolpackage visibility then theoutput property can't be public:Property cannot be declared public because its type uses a package type
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.
ah, makes sense – thanks for checking. maybe just as a matter of hygiene we should make the protocol underscored (_WorkflowOutputPublisher) and add comments regarding its purpose, since it doesn't seem like it's actually intended to be 'really' public.
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.
Sounds good.
mjohnson12Aug 25, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
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.
Pushed up the added underscore.
96bbd04 to7ce7d31CompareUh oh!
There was an error while loading.Please reload this page.
| letrootNode:WorkflowNode<WorkflowType> | ||
| privateletmutableRendering:MutableProperty<WorkflowType.Rendering> | ||
| privateletrenderingSubject:CurrentValueSubject<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.
slightly inclined to split the storage for the property vs the observer, since that will give us the most control over when the 'outside world' sees the update. e.g.
var rendering: Renderinglet renderingSubject = PassThroughSubject<Rendering, Never>()any thoughts on that? i guess one thing that would be different is that the old way (and presumably using a CVS) would have some baked-in synchronization mechanism over the underlying value. in theory this stuff should be main-thread-only though.
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 currently are using a ReactiveSwift MutableProperty which does have an internal lock. Yes CurrentValueSubject does have some baked in serialization mechanism albeit without Apple documentation on what that is. Since we can't enforce someone reading the rendering value on the main thread I'm inclined to use the CurrentValueSubject since it's about as close as we can get as a Combine version of what we have now.
If we split the storage for the property out we could always lock around getting/setting it so I'm not against doing that but I think CurrentValueSubject should work for how we are using it.
| publicvaroutput:Signal<Output,Never>{ | ||
| Signal.unserialized{ observer, lifetimein | ||
| letcancellable= outputPublisher.sink( | ||
| receiveCompletion:{ completionin | ||
| switch completion{ | ||
| case.finished: | ||
| observer.sendCompleted() | ||
| case.failure(let error): | ||
| observer.send(error: error) | ||
| } | ||
| }, | ||
| receiveValue:{ valuein | ||
| observer.send(value: value) | ||
| } | ||
| ) | ||
| lifetime.observeEnded{ | ||
| cancellable.cancel() | ||
| } | ||
| } |
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.
let's plan on testing this fairly thoroughly. i'm never certain what the exact lifetime semantics are for the ReactiveSwift stuff personally...
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.
Agreed. This has been in use in the ReactiveSwift bridging module for a while.
Workflow/Sources/WorkflowHost.swift Outdated
| publicprotocolWorkflowOutputPublisher{ | ||
| associatedtypeOutput | ||
| varoutputPublisher:AnyPublisher<Output,Never>{get} | ||
| } |
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.
ah gotcha (sorry i missed the existing convo). so the tradeoff here is adding a 'public' protocol to which we really only want 2 specific things to conform so that we don't need to makeWorkflow orWorkflowUI depend onReactiveSwift – is that right? mostly out of curiosity – is it possible to define the protocol withpackage visibility? that seems like it might be a slightly more accurate definition (assuming it works and integrates successfully into the monorepo).
jamieQ commentedAug 22, 2025
let's also include in the commit message something that clearly indicates this is a breaking change to the public API, a la the guidelines specified via 'conventional commits' |
7ce7d31 to99238f0Comparemjohnson12 commentedAug 22, 2025
I've updated the commit message |
99238f0 tof9c40fdComparef9c40fd to2fee5aaCompare2fee5aa to101286aComparerobmaceachern commentedOct 14, 2025
@mjohnson12 (PR cleanup) Does this need fresh reviews from folks, or should it be converted to a draft for now? |
mjohnson12 commentedOct 14, 2025
I need to rebase this to pickup Jamie's latest changes and then add some more tests but after the rebase I would like reviews on the changes |
1ff4a45 tod8f8562Comparewatt commentedDec 8, 2025
Doing some housekeeping, converting this back to draft to clear it out of review queues for now. Feel free to move it out of draft when you're ready for reviews again! |
BREAKING CHANGE: This changes the public interface of WorkflowHost and WorkflowHostingController.The rendering property is now a read only property of the RenderingThere is a new renderingPublisher property for a Combine publisher for renderingsThe output Signal property has been removed and moved to an extension in WorkflowReactiveSwiftThere is a new outputPublisher property for a Combine publisher for output
d8f8562 toeb185a5Compare
Uh oh!
There was an error while loading.Please reload this page.
This is a breaking change to Workflow that removes ReactiveSwift from the public interface of Workflow and Workflow UI.
There are 3 changes:
WorkflowHostrenderingis now a read only property of the latest rendering.WorkflowHostrenderingPublisheris a Combine publisher that publishes renderings. In searching the register code base there were very few places we were using aSignal/SignalProducerfrom therenderingproperty. The plan would be to change those consumers to userenderingPublisherandsink.WorkflowHostoutputhas been renamed tooutputPublisher. It is now a CombinePublisherthat can be used to subscribe to Workflow output. Per Andrew's suggestion I added a new protocolWorkflowOutputPubisherthat exposes theoutputPublisher. Theoutputproperty is used in a lot of places in register. To fix those places I added an extension onWorkflowOutputPubisherin WorkflowReactiveSwift that re-exposesoutputas aSignal. All the places that useoutputwill just need to import WorkflowReactiveSwift and they will continue to work.WorkflowHostingControllerin WorkflowUI now implementsWorkflowOutputPublisher. Consumers usingoutputwill 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