Cell Data Unbinding
Recently a user reported a bug of Moke:
Some pictures don't show if I scroll up immediately after scrolling down in a user album.
Fortunately I can reproduce it. After several hours' debugging I finally found the cause: cellForItemAtIndexPath
is not called for those UICollectionViewCell
s before they are displayed, i.e. before willDisplayCell
is called.
The missing of cellForItemAtIndexPath
calls doesn't occur usually, of course. Otherwise, all apps using UICollectionView
will break.
It only occurs for those cells that disappear and then immediately appear again—the user scrolls them out of bounds and then scrolls them back into bounds again. cellForItemAtIndexPath
is correctly called when they first appear.
Though this behavior was unexpected to me—that's why bugs happen—it is totally reasonable: cellForItemAtIndexPath
is for binding data to cell. If a cell's indexPath
doesn't change its corresponding data doesn't change—assuming the data source doesn't change—it can be reused as is without data rebinding.
Most apps won't be affected by this behavior because they only do data binding not data unbinding. But my app does data unbinding, out of my excessive care about memory usage.
The place I do data unbinding is didEndDisplayingCell
. Without the expected cellForItemAtIndexPath
call those cells don't have the chance to rebind to their data, hence show up empty.
Though this behavior currently only occurs for UICollectionView
. You should also take it into account when using UITableView
.
Conclusion:
didEndDisplayingCell
pairs withwillDisplayCell
notcellForItemAtIndexPath
orcellForRowAtIndexPath
.willDisplayCell
may be called without callingcellForItemAtIndexPath
orcellForRowAtIndexPath
first. The cell may be scrolled back into bounds immediately after being scrolled out of bounds while user is scrolling back and forth. In this situationwillDisplayCell
may be called afterdidEndDisplayingCell
withoutcellForItemAtIndexPath
orcellForRowAtIndexPath
in between.Data unbinding can be safely done in
didEndDisplayingCell
only if data binding is done inwillDisplayCell
. But normally data binding is done incellForItemAtIndexPath
orcellForRowAtIndexPath
so there is no safe and convenient place to do data unbinding.