Skip to content

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

@appleguy

Description

@appleguy

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions