Skip to content

Instantly share code, notes, and snippets.

@honghaoz
Last active August 29, 2015 14:11
Show Gist options
  • Save honghaoz/3bc6cbec2b22f66962c0 to your computer and use it in GitHub Desktop.
Save honghaoz/3bc6cbec2b22f66962c0 to your computer and use it in GitHub Desktop.
collection view perform batch update
// Compare old data model with new data model and perform batch update for collection view
/**
* Perform batch update on collection view, use old stories and new stories to make comparison
* groupId property of story is used for comparison
*
* PRE: make sure collection view's data model is update with newArray
*
* After animation completed, visible cells' view are updated
*
* @param oldArray Arrary of old stories, contains Story object
* @param newArray Arrary of new stories, contains Story object
*/
- (void)performBatchUpdateFromOldDataModel:(NSArray *)oldArray toNewDataModel:(NSArray *)newArray
{
// For the first time, when collection view is empty, call reloadData
if (oldArray.count == 0)
{
[self.collectionView reloadData];
return;
}
// Prepare groupIds for old stories and new stories, use id to compare
NSMutableArray *oldStoryIds = [[NSMutableArray alloc] initWithCapacity:oldArray.count];
for (Story *story in oldArray)
{
[oldStoryIds addObject:story.groupId];
}
NSMutableArray *newStoryIds = [[NSMutableArray alloc] initWithCapacity:newArray.count];
for (Story *story in newArray)
{
[newStoryIds addObject:story.groupId];
}
// If there's no changes, don't update
if ([oldStoryIds isEqualToArray:newStoryIds])
{
return;
}
// Arrays stores indic to be processed
NSMutableArray *deletedIndice = [[NSMutableArray alloc] init]; // [1, 2, 3 ...]
NSMutableArray *insertedIndice = [[NSMutableArray alloc] init]; // [1, 2, 3 ...]
NSMutableArray *movedIndice = [[NSMutableArray alloc] init]; // [[1, 3], [4, 2] ...]
// Old vs New, to initialize deleted indice and moved indice
// Init deleted indice, existing in Old but not in New
// Init moved indice, existing in both but indice are different
NSUInteger oldStoryIdsCount = [oldStoryIds count];
for (NSUInteger oldIdIndex = 0; oldIdIndex < oldStoryIdsCount; oldIdIndex++)
{
NSNumber *oldId = [oldStoryIds objectAtIndex:oldIdIndex];
if (![newStoryIds containsObject:oldId])
{
// Deleted
[deletedIndice addObject:@(oldIdIndex)];
}
else
{
NSMutableArray *OldIndexToNewIndex = [[NSMutableArray alloc] initWithCapacity:2];
NSUInteger newIdIndex = [newStoryIds indexOfObject:oldId];
// Moved
if (newIdIndex != oldIdIndex)
{
OldIndexToNewIndex[0] = @(oldIdIndex);
OldIndexToNewIndex[1] = @(newIdIndex);
[movedIndice addObject:OldIndexToNewIndex];
}
}
}
// New vs Old, to initialize inserted indice
// Init inserted indice, existing in New but not in Old
NSUInteger newStoryIdsCount = [newStoryIds count];
for (NSUInteger newIdIndex = 0; newIdIndex < newStoryIdsCount; newIdIndex++)
{
NSNumber *newId = [newStoryIds objectAtIndex:newIdIndex];
if (![oldStoryIds containsObject:newId])
{
// Inserted
[insertedIndice addObject:@(newIdIndex)];
}
}
// Perform collection view animation
__weak CurrentReadsViewController *weakSelf = self;
[self.collectionView performBatchUpdates:^{
// Delete
NSArray *deletedIndexPaths = [deletedIndice map:^id(NSNumber *indexToDelete, NSUInteger index) {
return [NSIndexPath indexPathForItem:[indexToDelete unsignedIntegerValue] inSection:0];
}];
[weakSelf.collectionView deleteItemsAtIndexPaths:deletedIndexPaths];
// Insert
NSArray *insertedIndexPaths = [insertedIndice map:^id(NSNumber *indexToInsert, NSUInteger index) {
return [NSIndexPath indexPathForItem:[indexToInsert unsignedIntegerValue] inSection:0];
}];
[weakSelf.collectionView insertItemsAtIndexPaths:insertedIndexPaths];
// Move
for (NSArray *oldIndexToNewIndexPair in movedIndice)
{
NSUInteger oldIndex = [oldIndexToNewIndexPair[0] unsignedIntegerValue];
NSUInteger newIndex = [oldIndexToNewIndexPair[1] unsignedIntegerValue];
NSIndexPath *fromIndexPath = [NSIndexPath indexPathForItem:oldIndex inSection:0];
NSIndexPath *toIndexPath = [NSIndexPath indexPathForItem:newIndex inSection:0];
[weakSelf.collectionView moveItemAtIndexPath:fromIndexPath toIndexPath:toIndexPath];
}
} completion:nil];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment