Skip to content

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

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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions