Did you get a chance to watch the WWDC 2016 session, “What’s New in UICollectionView in iOS10″ yet? I watched it today. There is some good stuff in the session, and I want to recap it for you in this post. The session is broken into three segments that capture everything that’s new for an iOS 10 UICollectionView :
- Smooth Scrolling
- Self-Sizing Cells
- Interactive Reordering
There is a special bonus fourth segment as well, but I’ll save that for later.
Smooth Scrolling Enhancements
In iOS 10, there are several enhancements that will improve the performance of your
UICollectionViews – some of which you will manually need to leverage, and some you will get for free. Before dropping into the new features of iOS 10 UICollectionView, the presenter gives a nice overview of what it means to “drop frames” and what it’s bad.
Don’t Drop Frames
In order for your app to have “buttery smooth” performance, a hallmark of iOS apps, you must strive for app animation that performs at 60 frames per second. This means that a given frame of the user interface must be displayed in less than 16.67ms in order for the animation to appear “smooth.” Otherwise, when the frame rate drops lower than that, it’s apparent to the user in the form of a choppy animation. The easiest way to make the frame rate drop, is to do things like add blocking, long running method calls on the main thread in the middle of your animation. Here’s an in-depth article from Facebook on how they measure and ensure a highly performant news feed in their app.
Less Aggressive Loading and Unloading Cells
UICollectionView, the lifecycle of a cell is as follows:
cellForItemAtIndexPath – The heavy lifting of populating your cell’s data from your model happens here.
willDisplayCell – Lightweight preparation for when you cell is about to go onscreen.
- Cell comes on screen, and as scrolling continues starts to move offscreen.
In general, this flow is unchanged between iOS 9 and iOS 10. The different is when these methods are called. Apple has optimized when
willDisplayCell is called. In iOS 10, it’s now called at the very last minute before the cell goes on screen. This helps to balance out the CPU performance in drawing cells, but not executing that code too early. Additionally, another enhancement Apple has made in iOS 10 UICollectionView is that cells are not put on the reuse queue as aggressively as in the past. Instead, after a cell leaves the screen, it is kept around a little longer in case the user decides to swipe the cell back on screen.
Apple also enhanced
UICollectionView such that by default, cells are pre-fetched. This means that you can get even earlier awareness of when data for a cell is needed such that you can retrieve it. For example, if you are building a
UICollectionView full of remote images. Leveraging the
UICollectionViewDataSourcePrefetching, UIKit will call:
to allow for you to start downloading the images with Grand Central Dispatch of an
NSOperationQueue such that when the cells containing the images comes on screen, the images will be downloaded and ready to go.
If you need to, you can opt out of this behavior by setting
false, but why would you?
As part of pre-fetching, realizing that
cellForItemAtIndexPath may be called for cells that never end up coming on screen – because the user stopped scrolling before they were shown. Also, it’s really important that you keep the work in
didEndDisplayingCell really light. All the heavy lifting goes in
cellForItemAtIndexPath. Apple described pre-fetching as an “adaptive technology” which I assume to mean that it’s level of “predictiveness” varies by use case for a given application.
And as bonus, this exact same pre-fetching API is also available on
Self Sizing Enhancements
Prior to iOS 10,
estimatedItemSize has existed on
UICollectionViewFlowLayout in order for you to provide an estimate size for the items in your collection view. Sometimes it’s hard to predict the size of items in your
UICollectionView. Realizing this, Apple has introduced automatic item sizing for your
UICollectionViewFlowLayout. Simple set the item size to the constant
UICollectionViewFlowLayoutAutomaticSize and UIKit will make smart guesses based on past measurements of your items in order to automatically predict item sizes for future items.
According to Apple:
It will keep a running tally of all the cells it’s already sized, and use that to influence its future sizing estimates…making the sizing much more accurate…leading to better performance and a more accurate layout.
Interactive Reordering Enhancements
Reordering a iOS 10 UICollectionView has also undergone some improvements as well. Prior to iOS 10, if you didn’t already know (and I only learned recently), it’s really easy to enable reordering on your
UICollectionView – in your
UICollectionViewDelegate, simply implement:
func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath
There are some additional methods on
UICollectionView that you should take a peak at too that enable you to add more advanced animation and update your data model if appropriate.
New in iOS 10 UICollectionView is the ability to reorder with paging!
collectionView.isPagingEnabled = true
That’s it! The presenter describes it as an interaction that feels just like moving icons between pages on your home screen.
Finally, the big reveal happens. It’s as if this is such exciting news worthy of a WWDC reveal, but there is no other session appropriate for it. The presenters reveal that pull to refresh will be supported on:
If it wasn’t awesome enough that
UICollectionView got the control, but you are also no longer constrained to needing a
UITableViewController if you want an out of the box pull to refresh control (which was a pretty annoying prior limitation in my opinion).
I have plans to do an in-depth example of how to use pre-fetching with Grand Central Dispatch in order load remote images in a
UITableView sometime in the future. I recently ran into a problem in one of my apps that this exact thing would have solved. Essentially I had cells in a
UITableView that were of varied height based on a remote
UIImage being loaded. I ended up needing to set a static height on the cells to achieve a high frame rate and scaling the images, instead of properly sizing the cells according to the natural height of the image. It wasn’t the end of the world, but there was some extra white space in the cells that wasn’t needed. How do you plan on using these new changes to iOS 10 UICollectionView?