简体   繁体   中英

Crash with UICollectionView and custom flow layout

I've implemented sticky section headers for a collection view, using http://blog.radi.ws/post/32905838158/sticky-headers-for-uicollectionview-using as a jumping off point, and they work.

But I'm seeing a very weird crash.

When I push an editor detail view, change the item's name such that it moves from one section to another ( think, changing the last name of a person in a contacts list which is grouped by first letter of last name), and then pop back to the collection view it crashes with a complaint

UICollectionView received layout attributes for a cell with an index path that does not exist

Here's the flow of execution:

In the editor detail view, I change the item's name such that it will move from section X to section Y.

The item's model emits a "name changed" notification.

The root view controller which owns the collection view catches that "name changed" notification, rebuilds its internal indexes, and then calls -reloadData on the collection view. This is all good.

I hit the Back button in the UI, and the following flow happens ( confirmed via debugger and caveman NSlog calls )

  • numberOfSectionsInCollectionView: is called, and my code returns correct number of sections
  • collectionView:numberOfItemsInSection: is called for each section, and correct number of items is returned
  • my custom flow layout's -layoutAttributesForElementsInRect: is called. The first thing I do in there is call [super layoutAttributesForElementsInRect] to get a baseline layout.

Logging the the inherited baseline layout I see attributes for the previous arrangement of cells, not the current one. Eg, the layout is for the arrangement before the edits I just made. So, incorrect sections and or cells in incorrect sections.

Now here's what blows my mind.

If I comment out the entire implementation of -layoutAttributesForElementsInRect, it still crashes. But, if I comment out:

- (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBound {
    return YES;
}

Then, it works correctly.

This tells me that the collection view, or something in flow layout is caching results, but only if the flow layout shouldInvalidateLayoutForBoundsChange

Note, if I just use a vanilla UICollectionViewFlowLayout everything works fine.

TLDR

Custom UICollectionViewFlowLayout, if -shouldInvalidateLayoutForBoundsChange returns YES, gets out-of-date layout attributes from [super layoutAttributesForElementsInRect]

Any ideas?

I solved this by removing the shouldInvalidateLayoutForBoundsChange: override, and instead implementing scrollViewDidScroll: on the collection view's delegate to invalidate layout:

override func scrollViewDidScroll(scrollView: UIScrollView) {
    collectionView?.collectionViewLayout.invalidateLayout()
}

This keeps the sticky headers but stops the crashing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM