-
Notifications
You must be signed in to change notification settings - Fork 45
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
Allow lifecycle callbacks to safety trigger re-renders #425
Conversation
|
||
var temporaryWindow: UIWindow? = nil | ||
|
||
func rootViewController() -> UIViewController { |
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 two cases in here ensure we can run the tests in both cocoapods world, which provides an app host, and SPM, which does not (there is no option in SPM to provide an app host).
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.
Hmm, are you sure this is necessary? The existing lifecycle tests work fine without an app host.
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'm trying to make it work/exist as close to as possible to a "real" UI – hence pulling in the app host changes. While it passed before, there's enough special UIKit behavior that exists when being in a real app that I'd rather we just mirror real apps as much as possible.
/// This is inc ase the `onAppear` callback triggers a re-render, | ||
/// we don't hit our recurisve update precondition. |
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 dunno, this makes me nervous. If we allow this then you can get into weird scenarios where there's a render pass with callbacks, and it forces another layout which also has callbacks, and now they're out of order — the recursive render gets to complete its callbacks before the first one. In the worst case you could kick off a loop that never allows the render to complete.
Fundamentally I'm not sure there's a strong justification for anyone needing to force an explicit re-render during onAppear
. Why did the element need to change as a result of appearing, instead of just using that element to begin with? Why did it need to change immediately and synchronously? Seems like there are some holes in this story.
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 this change is good. I'm not sure if the debug warning we were talking about has a ton of value, so I can live without it.
The nested callback case pointed out by Andrew is interesting but I'm not 100% sure if we need to address that.
Co-authored-by: Robert MacEachern <[email protected]>
Once again, annoyed about the extension thing
|
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.
just discovered I had this pending review from a while ago
|
||
var temporaryWindow: UIWindow? = nil | ||
|
||
func rootViewController() -> UIViewController { |
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.
Hmm, are you sure this is necessary? The existing lifecycle tests work fine without an app host.
@@ -1,16 +1,16 @@ | |||
import UIKit | |||
|
|||
/// View which does not personally receive touches but allows its subviews to receive touches. | |||
final class PassthroughView: UIView { | |||
@_spi(BlueprintPassthroughView) public final class PassthroughView: UIView { |
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.
Can you pull out these unrelated changes?
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.
Not unrelated; moving LifecycleObserver
, which depends on PassthroughView
, means we need to expose 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.
(Also sorry, to be clear, one of the reasons I moved this was to get this running under our cocoapods tests – which right now does not run any of the CommonControls tests...)
This fixes an issue where folks would in some cases have to
Dispatch.async
the work they perform in theironAppear
(or `onDisappear) blocks, because the lifecycle callbacks were triggered inside the update. They're not really parts of the render semantically (they more mean "the layout is done, now the element is visible), so this seems more correct.To properly test this, I had to move some stuff around:
BlueprintUI
, since it's not really a "control".PassthroughView
and moved it intoBlueprintUI
as well.