I am trying to find the best way to handle state restoration for a UICollectionView whose elements may move around. My goal is to make sure that the last viewed item in the collection view is still visible when restarting the app, even if the items have moved around. For example, item A is in cell at index 3 when the app was killed, and when the app restarts if the model says that item A should be displayed at index 4, I want the collection view to initialize offset to the cell at index 4.
I thought that implementing the UIDataSourceModelAssociation
protocol in my UICollectionViewDataSource
class would take care of this for me, as the documentation states:
[UITableView and UICollectionView] classes use the methods of this protocol to ensure that the same data objects (and not just the same row indexes) are scrolled into view and selected.
However, what I have observed is that implementing this protocol does properly affect the indexPath of the selected cells during restoration (which isn't important to my app), but it does not affect the scroll position. The scroll position (contentOffset of the collection view) is always restored to exactly where it was when the app was killed, and not affected by the UICollectionViewDataSource.
I do have a workaround that looks like this. It's basically the same pattern as the model assocation protocol, but I have to do it manually:
override func encodeRestorableStateWithCoder(coder: NSCoder) {
let identifier = determineIdOfCurrentlyVisibleCell()
coder.encodeObject(identifier, forKey: "visibleCellIdentifier")
}
override func decodeRestorableStateWithCoder(coder: NSCoder) {
if let identifier = coder.decodeObjectForKey("visibleCellIdentifier") as? String {
if let indexPath = model.indexPathForIdentifier(identifier) {
collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .CenteredVertically, animated: false)
}
}
}
Did I misunderstand the usage of UIDataSourceModelAssociation? Is there a bug? Is there a more elegant or correct way to get this to work?