Setup: I have a UICollectionView or UITableView that’s backed by a simple array data source. I keep a copy of that data source in the controller.
Now, I get a notification from the system that there’s new data available. I get a new array where items may have been added, removed and changed positions.
So now I have two data objects:
- previous array that’s in sync with what the UI is currently showing
- new array where items have been added, removed, moved
To get the UI in sync with the new array, I need to generate a bunch of UI calls. In case of UICollectionView, those are
- (void)insertItemsAtIndexPaths:(NSArray *)indexPaths
- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath
- (void)deleteItemsAtIndexPaths:(NSArray *)indexPaths
And there’s a similar set of methods for UITableView.
I specifically don’t want to reload the whole table because that’s more expensive than just working with a few items.
So, the question is: given the previous and new data source array, how do I generate the correct set of UI calls, and when do I “swap out” my old data source for the new?
I’d see this as largely equivalent to the diff / patch problem, where the aim is to find the minimal number of changes between one text file and another and then to apply those changes. In that case, the implementation defines the operations:
… but not move. The reason for omitting move isn’t immediately obvious to me but I’d strongly suspect that including move would require a very costly computation to find the optimal movement.
So, if we restrict the operations to those listed above, the Hunt-McIlroy algorithm described in An Algorithm for Differential File Comparison, or one of its descendents, would find a close-to-optimal set of changes.
The difference between your problem and the classic diff / patch is that you have a two-dimensional table, while diff / patch deals with a one-dimensional set of items (lines of text). The best way to convert the 2-D problem into the 1-D problem would depend on the particular characteristics of the changes that tend to be made in your data table.
For example, if the table is n rows by m columns and changes tend to be grouped in rows or rows are inserted or deleted as a whole, then you would likely be best to consider the table as if it was a text file and do the diff line by line. Alternatively, if changes tend to be grouped in columns or columns are inserted or deleted, you could do the diff column by column. If the alterations include inserting or deleting individual cells (which result in the subsequent cells shifting right or left as a result), you could treat the table as if each cell in the table was on a separate line of the text file, linearising the table in either row-first or column-first order.
Without knowing the details of your problem in this respect, however, my inclination would be to avoid premature optimisation. Thus, I’d tend to start by implementing the Hunt-McIlroy algorithm row-by-row if m < n, or column-by-column if n < m, then profile the application in use for a while before deciding that either a more sophisticated version of the algorithm or an alternative mapping of your problem to the Hunt-McIlroy solution was warranted.
A good discussion of a variety of diff algorithms can be found here on stackoverflow.