Cancel in-progress reorders when the list is torn down - #630
Draft
elizrus wants to merge 1 commit into
Draft
Conversation
A reorder gesture drives a native UICollectionView interactive-movement session that expects to be resolved with endInteractiveMovement or cancelInteractiveMovement. If the list leaves the window or is deallocated while a drag is still held — for example, the user navigates away mid-drag — nothing ends that session. It outlives the content it was started against, so a later content update or layout pass reads a now-stale index and traps in the layout (Index out of range in ListLayoutContent.item(at:)). Cancel any in-progress reorder in didMoveToWindow when leaving the window, and in deinit, while the data source and layout are still in sync. Both are guarded by hasInProgressReorders so they are no-ops in the common case. Add regression tests covering the window-removal and deinit teardown paths. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a crash when a list is torn down while an interactive reorder is still in progress — for example, the user navigates away (taps a nav-bar shortcut, pops the screen) while still holding a drag.
A reorder gesture drives a native
UICollectionViewinteractive-movement session, which UIKit expects to be resolved withendInteractiveMovement()orcancelInteractiveMovement(). Today nothing ends that session when the list leaves the window or is deallocated:deinitonly nilscollectionView.delegate/dataSource.didMoveToWindow()does nothing whenwindow == nil.cancelAllInProgressReorders()is the content-diff-apply path (guarded byhasInProgressReorders, and annotated as experimental/"will likely crash").So the interactive-movement session outlives the content it was started against. A later content update or layout pass then reads a now-stale index and traps:
(also observed via
CollectionViewLayout.positionForItem(at:)←ListView.setPresentationStateItemPositions().)Change
Cancel any in-progress reorder while the data source and layout are still in sync:
didMoveToWindow()when the list leaves the window (the navigate-away-mid-drag case).deinitas a backstop.Both are guarded by
hasInProgressReorders, so they are no-ops in the common case.hasInProgressReordersis relaxed fromprivateto internal so tests can assert on it.Testing
Adds
ListView.ReorderTeardownTestscovering both teardown paths (window removal and deinit). Verified the reorder state is cleared on window exit and that deallocation with a live reorder does not crash.Reported from Square Point of Sale: app crashes when a payment type is dragged between sections in Payment settings and a navigation-bar shortcut is tapped mid-drag.
Checklist
Mainsection.