-
Notifications
You must be signed in to change notification settings - Fork 47
[fix]: update WorkflowHostingController on layout if ancestor hierarchy has changed #227
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
Conversation
10c5a29
to
0c16447
Compare
…rarchy has changed
0c16447
to
cf696af
Compare
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.
Clever!
applyEnvironmentIfNeeded() | ||
|
||
let environmentAncestorPath = environmentAncestorPath | ||
if environmentAncestorPath != lastEnvironmentAncestorPath { |
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.
Should we not do this if the path is empty? Eg, trying to think if a layout subviews can/will happen after being removed from the hierarchy, causing an extra or invalid layout pass.
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.
The WorkflowHostingController
could be become the root of a window where there would be no ancestor node and I think we'd still want to perform an update in that case.
@@ -41,6 +41,8 @@ public final class WorkflowHostingController<ScreenType, Output>: WorkflowUIView | |||
|
|||
private let (lifetime, token) = Lifetime.make() | |||
|
|||
private var lastEnvironmentAncestorPath: EnvironmentAncestorPath? |
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.
I think we might have a potential retain cycle here, if this is storing strong references to the entire VC hierarchy above it. Can we weak-box each ancestor on the path, or does that break our ability to reliably compare paths?
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's not a reference since it uses ObjectIdentifier(node)
right? Eg, just a pointer.
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.
That's also my understanding.
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.
I talked through this with @watt and did some experimentation locally and it does look like ObjectIdentifier
just keeps a reference to the pointer value, not the object itself.
One interesting note that @watt pointed out from the documentation of ObjectIdentifier
:
This unique identifier is only valid for comparisons during the lifetime of the instance.
Andrew was wondering if the pointer could be reused for a new instance and cause false positives on the equitability check.
This seems fairly unlikely to occur in practice here, but we could add a weak box for these objects to better track the lifetime if we think it's worth the effort.
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.
I've updated this to use a weak box and ===
comparisons: fa85e0f
Problem
When a
WorkflowHostingController
is added to aUIViewController
hierarchy, we need to ensure that we re-render theScreen
using an updatedViewEnvironment
, since the environment from the ancestor path above thatWorkflowHostingController
could contain customizations that are not present in theWorkflowHostingController
itself.Currently, it is expected that consumers would call
setNeedsEnvironmentUpdate()
when adding aWorkflowHostingController
as a child, but this is fragile and hard to enforce/validate, especially in legacy code.Omitting this
setNeedsEnvironmentUpdate()
can cause issues where content would be rendered on screen using invalidViewEnvironment
values on the first rendering. On a later environment update, we'd likely see this environment reflect the correct values, but we want to avoid showing content with badViewEnvironment
information whenever possible. An example of this issue can be seen in this Slack thread from a in issue reported inios-register
.Solution
While consumers should still try to call
setNeedsEnvironmentUpdate()
whenever the environment changes (either through an update in value or an update in path), this PR attempts to catch mistakes and legacy usecases by tracking the ancestor tree node path when state updates and layouts occur, and if that path changes, we'll ensure an update occurs on the next layout pass.Integration
I've smoke tested this change in
ios-register
andmarket
and no changes are needed upstream to support this fix. Here are the integration PRs (with no real code changes) that show passing CI jobs:ios-register
: https://github.com/squareup/ios-register/pull/88056market
: https://github.com/squareup/market/pull/6547