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

[ASCollection] When using supplementary items, rotation may not invalidateLayout early enough. #430

Open
appleguy opened this issue Jul 9, 2017 · 1 comment

Comments

@appleguy
Copy link
Member

appleguy commented Jul 9, 2017

The intention of the code in - (void)layer:(CALayer *)layer didChangeBoundsWithOldValue:(CGRect)oldBounds newValue:(CGRect)newBounds, implemented in ASCollectionView, is to force a relayout of the ASCellNodes at the new size — and then have the UICV update its layout to reflect these new values.

However, there are two potential issues with this:

  • In the case of this crash, the act of performing cell relayout somehow performs a batch update on the collection, which triggers it to perform a layout pass -- thus jumping ahead to a point where the layout should already be invalidated.
  • Because invalidateLayout doesn't in itself trigger any actions, it may be safe to perform before the cell relayout
  • Finally, because of recent changes to use layoutThatFits: rather than -calculatedSize when answering queries from UICollectionView for sizes, we may be able to completely eliminate the forced relayoutAllNodes-and-wait -- and instead rely on UICV's queries to synchronously fetch the layout for the cells it needs.
  • If we did this latter option, we might still want to kick off an asynchronous (but not block-and-wait) relayout of all nodes, so that as the user then continues to scroll down, they don't experience synchronous layout stalls.

@nguyenhuy @Adlai-Holler @maicki

2017-07-09 15:27:55.059 CollectionsStressBinary[17127:22633698] *** Assertion failure in -[UICollectionViewData validateLayoutInRect:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3600.7.47/UICollectionViewData.m:445
2017-07-09 15:27:55.111 CollectionsStressBinary[17127:22633698] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'layout attributes for supplementary item at index path (<NSIndexPath: 0xc000000001600116> {length = 2, path = 1 - 11}) changed from <UICollectionViewLayoutAttributes: 0x6080001e7700> index path: (<NSIndexPath: 0xc000000001600116> {length = 2, path = 1 - 11}); element kind: (YTSeparatorKind); frame = (0 520; 320 17);  to <UICollectionViewLayoutAttributes: 0x6080001e6600> index path: (<NSIndexPath: 0xc000000001600116> {length = 2, path = 1 - 11}); element kind: (YTSeparatorKind); frame = (0 520; 480 17);  without invalidating the layout'
*** First throw call stack:
(
	0   CoreFoundation                      0x0000000119457b0b __exceptionPreprocess + 171
	1   libobjc.A.dylib                     0x0000000118ebc141 objc_exception_throw + 48
	2   CoreFoundation                      0x000000011945bcf2 +[NSException raise:format:arguments:] + 98
	3   Foundation                          0x0000000111970536 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 193
	4   UIKit                               0x000000011278f039 __45-[UICollectionViewData validateLayoutInRect:]_block_invoke + 1367
	5   UIKit                               0x000000011278e55d -[UICollectionViewData validateLayoutInRect:] + 2964
	6   UIKit                               0x000000011273633e -[UICollectionView layoutSubviews] + 233
	7   CollectionsStressBinary             0x000000010fbd6d3a -[ASCollectionView layoutSubviews] + 618
	8   CollectionsStressBinary             0x000000010f11cf5e -[YTAsyncCollectionView layoutSubviews] + 94
	9   UIKit                               0x0000000111ebc55b -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1268
	10  QuartzCore                          0x0000000113dc5904 -[CALayer layoutSublayers] + 146
	11  CollectionsStressBinary             0x000000010fd2404e -[_ASDisplayLayer layoutSublayers] + 414
	12  QuartzCore                          0x0000000113db9526 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 370
	13  UIKit                               0x0000000111eaa334 -[UIView(Hierarchy) layoutBelowIfNeeded] + 1108
	14  UIKit                               0x000000011274e455 -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:animator:] + 246
	15  UIKit                               0x000000011274e33c -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:] + 91
	16  UIKit                               0x000000011274e2be -[UICollectionView _performBatchUpdates:completion:invalidationContext:] + 74
	17  UIKit                               0x000000011274e213 -[UICollectionView performBatchUpdates:completion:] + 53
	18  CollectionsStressBinary             0x000000010fbca50a -[ASCollectionView _superPerformBatchUpdates:completion:] + 570
	19  CollectionsStressBinary             0x000000010fbdefdf __67-[ASCollectionView rangeController:didUpdateWithChangeSet:updates:]_block_invoke + 895
	20  CollectionsStressBinary             0x000000010fbdec19 _ZL30ASPerformBlockWithoutAnimationbU13block_pointerFvvE + 137
	21  CollectionsStressBinary             0x000000010fbdea0a -[ASCollectionView rangeController:didUpdateWithChangeSet:updates:] + 1034
	22  CollectionsStressBinary             0x000000010fd05be8 -[ASRangeController dataController:didUpdateWithChangeSet:updates:] + 632
	23  CollectionsStressBinary             0x000000010fce58c2 __40-[ASDataController updateWithChangeSet:]_block_invoke_2 + 370
	24  CollectionsStressBinary             0x000000010fcf3d12 __30-[ASMainSerialQueue runBlocks]_block_invoke + 322
	25  CollectionsStressBinary             0x000000010fda8ce3 ASPerformBlockOnMainThread + 115
	26  CollectionsStressBinary             0x000000010fcf3b4b -[ASMainSerialQueue runBlocks] + 123
	27  CollectionsStressBinary             0x000000010fcf3a34 -[ASMainSerialQueue performBlockOnMainThread:] + 212
	28  CollectionsStressBinary             0x000000010fceae3a -[ASDataController _scheduleBlockOnMainSerialQueue:] + 522
	29  CollectionsStressBinary             0x000000010fce9cc9 -[ASDataController relayoutAllNodes] + 521
	30  CollectionsStressBinary             0x000000010fbe1d6e -[ASCollectionView layer:didChangeBoundsWithOldValue:newValue:] + 638
	31  CollectionsStressBinary             0x000000010fd236e1 -[_ASDisplayLayer setBounds:] + 1937
	32  QuartzCore                          0x0000000113dbc8a2 -[CALayer setFrame:] + 691
	33  UIKit                               0x0000000111e9cfe9 -[UIView(Geometry) setFrame:] + 845
	34  UIKit                               0x0000000111ecb3e6 -[UIScrollView setFrame:] + 149
	35  UIKit                               0x00000001127297ee -[UICollectionView setFrame:] + 615
	36  Foundation                          0x00000001119bb7b0 ___NSSetRectValueAndNotify_block_invoke + 73
	37  Foundation                          0x00000001119bc8c2 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:usingBlock:] + 791
	38  Foundation                          0x00000001118a4f8c -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 61
	39  Foundation                          0x0000000111961f2e _NSSetRectValueAndNotify + 325
	40  UIKit                               0x0000000111fdb3ae -[UINavigationController _layoutViewController:] + 1402
	41  UIKit                               0x0000000111fda2be -[UINavigationController _layoutTopViewController] + 338
	42  UIKit                               0x0000000111fcf61a -[UINavigationController _repositionPaletteWithNavigationBarHidden:duration:shouldUpdateNavigationItems:] + 387
	43  UIKit                               0x0000000111fd87f7 -[UINavigationController _updateBarsForCurrentInterfaceOrientation] + 77
	44  UIKit                               0x0000000111fe4062 __84-[UINavigationController willTransitionToTraitCollection:withTransitionCoordinator:]_block_invoke + 670
	45  UIKit                               0x000000011292d0d5 -[_UIViewControllerTransitionCoordinator _applyBlocks:releaseBlocks:] + 294
	46  UIKit                               0x00000001129292ee -[_UIViewControllerTransitionContext __runAlongsideAnimations] + 193
	47  UIKit                               0x0000000112484a3b __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke_2 + 180
	48  UIKit                               0x0000000111eb6fad +[UIView(Internal) _performBlockDelayingTriggeringResponderEvents:] + 188
	49  UIKit                               0x0000000112484848 __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke + 136
	50  UIKit                               0x0000000111eb23da +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] + 572
	51  UIKit                               0x0000000111eb28dd +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] + 99
	52  UIKit                               0x000000011248472e -[_UIWindowRotationAnimationController animateTransition:] + 513
	53  UIKit                               0x0000000111e6d47a -[UIWindow _rotateToBounds:withAnimator:transitionContext:] + 605
	54  UIKit                               0x0000000111e70144 -[UIWindow _rotateWindowToOrientation:updateStatusBar:duration:skipCallbacks:] + 1865
	55  UIKit                               0x0000000111e70b9b -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:isRotating:] + 726
	56  UIKit                               0x0000000111e6f83c -[UIWindow _setRotatableViewOrientation:updateStatusBar:duration:force:] + 141
	57  UIKit                               0x0000000111e6e4f3 __57-[UIWindow _updateToInterfaceOrientation:duration:force:]_block_invoke + 112
	58  UIKit                               0x0000000111e6e381 -[UIWindow _updateToInterfaceOrientation:duration:force:] + 485

@appleguy
Copy link
Member Author

appleguy commented Jul 9, 2017

Here is the method in question:

image

appleguy added a commit that referenced this issue Jul 9, 2017
nguyenhuy pushed a commit that referenced this issue Oct 24, 2017
…nds changes. (#431)

* [ASCollectionView] Improve performance and behavior of rotation / bounds changes.

See #430 for details.

* Edit CHANGELOG.md

* [ASDataController] Implement -relayoutAllNodesWithInvalidationBlock:, to flush the ASMainSerialQueue before -invalidateLayout is called.

* Don't set download results if no longer in preload range. (#606)

Good catch by @djblake, if you scroll fast enough, you leave images
set on the image node because didExitPreloadRange (which would have
cleared it) was already called.

* Animated WebP support (#605)

* Updating to support animated WebP

* Fix a deadlock with display link

* Fix playhead issue.

* Fix up timing on iOS 10 and above

* Don't redraw the same frame over and over

* Clear out layer contents if we're an animated GIF on exit range

* Clear out cover image on exit of visible range

* Don't set cover image if we're no longer in display range.

* Don't clear out image if we're not an animated image

* Only set image if we're not already animating

* Get rid of changes to podfile

* Add CHANGELOG entry

* Update license

* Update PINRemoteImage

* Remove commented out lines in example

* [ASDataController] Add nullable specifier to invalidationBlock for relayout of nodes.
bernieperez pushed a commit to AtomTickets/Texture that referenced this issue Apr 25, 2018
…nds changes. (TextureGroup#431)

* [ASCollectionView] Improve performance and behavior of rotation / bounds changes.

See TextureGroup#430 for details.

* Edit CHANGELOG.md

* [ASDataController] Implement -relayoutAllNodesWithInvalidationBlock:, to flush the ASMainSerialQueue before -invalidateLayout is called.

* Don't set download results if no longer in preload range. (TextureGroup#606)

Good catch by @djblake, if you scroll fast enough, you leave images
set on the image node because didExitPreloadRange (which would have
cleared it) was already called.

* Animated WebP support (TextureGroup#605)

* Updating to support animated WebP

* Fix a deadlock with display link

* Fix playhead issue.

* Fix up timing on iOS 10 and above

* Don't redraw the same frame over and over

* Clear out layer contents if we're an animated GIF on exit range

* Clear out cover image on exit of visible range

* Don't set cover image if we're no longer in display range.

* Don't clear out image if we're not an animated image

* Only set image if we're not already animating

* Get rid of changes to podfile

* Add CHANGELOG entry

* Update license

* Update PINRemoteImage

* Remove commented out lines in example

* [ASDataController] Add nullable specifier to invalidationBlock for relayout of nodes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant