Skip to content
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

Fix router getting stuck under certain circumstances #7536

Closed
wants to merge 1 commit into from

Conversation

rablador
Copy link
Contributor

@rablador rablador commented Jan 28, 2025

Somehow, Emīls manages to get the router to get stuck, which results in no button in the connect view navigating to any other view.

Jon believes we could just remove the queue from the router, that would remove the blocking behavior. It seems that the the router is just not removing work from the queue, seemingly being stuck.

This PR removes route validation and queueing, making the router simpler and easier to work with.


This change is Reviewable

@rablador rablador added bug iOS Issues related to iOS labels Jan 28, 2025
@rablador rablador self-assigned this Jan 28, 2025
Copy link

linear bot commented Jan 28, 2025

@rablador rablador force-pushed the router-gets-stuck-ios-970 branch 2 times, most recently from 868beab to 2f226ed Compare January 29, 2025 09:02
@rablador rablador force-pushed the router-gets-stuck-ios-970 branch from 2f226ed to 81548e6 Compare January 29, 2025 09:07
@rablador rablador marked this pull request as ready for review January 29, 2025 09:58
@rablador rablador force-pushed the router-gets-stuck-ios-970 branch from 81548e6 to 99ff117 Compare January 29, 2025 09:58
Copy link
Contributor Author

@rablador rablador left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 17 files reviewed, 1 unresolved discussion


ios/Routing/Router/ApplicationRouter.swift line 14 at r1 (raw file):

/**
 Main application router.

Note: It's probably easier to skip trying to figure out this diff and simply reading the file from scratch instead. The logic is a lot easier to follow and should be easy to understand without seeing the changes.

Copy link
Contributor

@SteffenErn SteffenErn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 17 files reviewed, 2 unresolved discussions (waiting on @rablador)


ios/Routing/Router/ApplicationRouter.swift line 143 at r1 (raw file):

                    routes.append(PresentedRoute(route: route, coordinator: coordinator))
                    self?.presentedRoutes[group] = routes
                }

Adding the routes to the presentedRoutes array in the completion handler leads to a race condition where a route can not be dismissed before it is fully presented (aka animation is done).
Ran into this issue when showing an overlaying spinner that gets dismissed when the network call was successful (which can be before the presenting animation is done) Calling dismiss on that route had no effect since it was not yet in the presentedRoutes array.
Earlier the dismiss call was queued and executed once the presentation was done I believe.

Copy link
Contributor Author

@rablador rablador left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 17 files reviewed, 2 unresolved discussions (waiting on @SteffenErn)


ios/Routing/Router/ApplicationRouter.swift line 143 at r1 (raw file):

Previously, SteffenErn (Steffen Ernst) wrote…

Adding the routes to the presentedRoutes array in the completion handler leads to a race condition where a route can not be dismissed before it is fully presented (aka animation is done).
Ran into this issue when showing an overlaying spinner that gets dismissed when the network call was successful (which can be before the presenting animation is done) Calling dismiss on that route had no effect since it was not yet in the presentedRoutes array.
Earlier the dismiss call was queued and executed once the presentation was done I believe.

Good catch! Will fix this and potentially other places.

Copy link
Contributor Author

@rablador rablador left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 17 files reviewed, 2 unresolved discussions (waiting on @SteffenErn)


ios/Routing/Router/ApplicationRouter.swift line 143 at r1 (raw file):

Previously, rablador (Jon Petersson) wrote…

Good catch! Will fix this and potentially other places.

Hmm, not so easy to fix it seems. The (later) dismissal needs a reference to the coordinator that was presented, which will not be available until presentation is done. We could change it so that ApplicationCoordinator completes before presentation (when the soon-to-be-presented coordinator has been created), but it would also mean that we need to assume it happened no matter the actual result. Maybe that's fine.

Copy link
Contributor Author

@rablador rablador left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 17 files reviewed, 2 unresolved discussions (waiting on @SteffenErn)


ios/Routing/Router/ApplicationRouter.swift line 143 at r1 (raw file):

Previously, rablador (Jon Petersson) wrote…

Hmm, not so easy to fix it seems. The (later) dismissal needs a reference to the coordinator that was presented, which will not be available until presentation is done. We could change it so that ApplicationCoordinator completes before presentation (when the soon-to-be-presented coordinator has been created), but it would also mean that we need to assume it happened no matter the actual result. Maybe that's fine.

In fact, we already to this for many exisiting routes...

@rablador rablador force-pushed the router-gets-stuck-ios-970 branch from 99ff117 to 8f29add Compare January 30, 2025 08:53
Copy link
Contributor

@buggmagnet buggmagnet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 10 of 17 files at r1.
Reviewable status: 9 of 17 files reviewed, 3 unresolved discussions (waiting on @rablador and @SteffenErn)


ios/RoutingTests/RoutingTests.swift line 51 at r2 (raw file):

        XCTAssertFalse(router.isPresenting(route: .one))
    }

Currently, there are no tests that test the logic in either dismiss(route:animated:) or dismiss(group: animated:)
We should definitely add tests that cover this behaviour.

Copy link
Contributor

@buggmagnet buggmagnet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 9 of 17 files reviewed, 4 unresolved discussions (waiting on @rablador and @SteffenErn)


ios/Routing/Router/ApplicationRouter.swift line 161 at r2 (raw file):

        delegate.applicationRouter(self, handleSubNavigationWithContext: context) { [weak self] in
            MainActor.assumeIsolated {

If we mark the closure in handleSubNavigationWithContext as @MainActor we can get rid of this MainActor.assumeIsolated

SteffenErn
SteffenErn previously approved these changes Feb 3, 2025
Copy link
Contributor

@SteffenErn SteffenErn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 16 of 17 files at r1, 1 of 1 files at r2, all commit messages.
Reviewable status: all files reviewed, 3 unresolved discussions (waiting on @rablador)


ios/Routing/Router/ApplicationRouter.swift line 143 at r1 (raw file):

Previously, rablador (Jon Petersson) wrote…

In fact, we already to this for many exisiting routes...

Might be too much for this ticket to fix all quirks of the router. I worked around this behavior and it's no longer an issue for me.

Copy link
Contributor Author

@rablador rablador left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: all files reviewed, 3 unresolved discussions (waiting on @buggmagnet)


ios/Routing/Router/ApplicationRouter.swift line 161 at r2 (raw file):

Previously, buggmagnet wrote…

If we mark the closure in handleSubNavigationWithContext as @MainActor we can get rid of this MainActor.assumeIsolated

I've tried many variants here, but doing this results in the following error:
Converting function value of type '@MainActor @Sendable () -> Void' to '@Sendable () -> Void' loses global actor 'MainActor'

Copy link
Contributor Author

@rablador rablador left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 15 of 17 files reviewed, 3 unresolved discussions (waiting on @buggmagnet and @SteffenErn)


ios/RoutingTests/RoutingTests.swift line 51 at r2 (raw file):

Previously, buggmagnet wrote…

Currently, there are no tests that test the logic in either dismiss(route:animated:) or dismiss(group: animated:)
We should definitely add tests that cover this behaviour.

Done.

@rablador rablador force-pushed the router-gets-stuck-ios-970 branch from d96322c to 5696e16 Compare February 6, 2025 12:24
@rablador rablador force-pushed the router-gets-stuck-ios-970 branch from 5696e16 to 9ae5e47 Compare February 6, 2025 13:49
@rablador rablador closed this Feb 7, 2025
@rablador rablador deleted the router-gets-stuck-ios-970 branch February 20, 2025 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug iOS Issues related to iOS
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants