Reputation: 587
So I have NSMutableArray of NSDictionary items. Each NSDictionary item has a key "name" that should be used to sort the array alphabetically. Except its "sorting" partially works. Its not sorting in exact alphabetical order. It's moving some of the dictionary in order, but leaves some out of order.
NSMutableArray *section1 = [champs lastObject];
NSArray *oldSection1 = [NSArray arrayWithArray:section1];
[section1 sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDictionary *dictA = (NSDictionary *)obj1;
NSDictionary *dictB = (NSDictionary *)obj2;
NSString *champName1 = dictA[@"name"];
NSString *champName2 = dictB[@"name"];
return [champName1 compare:champName2];
}];
// Animation
for (NSDictionary *champInfo2 in section1) {
if ([oldSection1 indexOfObject:champInfo2] != [section1 indexOfObject:champInfo2]) {
[self.collectionView moveItemAtIndexPath:[NSIndexPath indexPathForItem:[oldSection1 indexOfObject:champInfo2] inSection:1] toIndexPath:[NSIndexPath indexPathForItem:[section1 indexOfObject:champInfo2] inSection:1]];
}
}
I even tried this code
NSMutableArray *section1 = [champs lastObject];
NSArray *oldSection1 = [NSArray arrayWithArray:section1];
/*[section1 sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDictionary *dictA = (NSDictionary *)obj1;
NSDictionary *dictB = (NSDictionary *)obj2;
NSString *champName1 = dictA[@"name"];
NSString *champName2 = dictB[@"name"];
return [champName1 compare:champName2];
}];*/
section1 = [[NSArray arrayWithArray:section1] sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]].mutableCopy;
// Animation
for (NSDictionary *champInfo2 in section1) {
if ([oldSection1 indexOfObject:champInfo2] != [section1 indexOfObject:champInfo2]) {
[self.collectionView moveItemAtIndexPath:[NSIndexPath indexPathForItem:[oldSection1 indexOfObject:champInfo2] inSection:1] toIndexPath:[NSIndexPath indexPathForItem:[section1 indexOfObject:champInfo2] inSection:1]];
}
}
Ok so the problem was I wasn't updating my snapshot of the content before reorganization as I updated it visually. Updated code:
// Animation
for (NSDictionary *champInfo2 in section) {
if ([oldSection indexOfObject:champInfo2] != [section indexOfObject:champInfo2]) {
[self.collectionView moveItemAtIndexPath:[NSIndexPath indexPathForItem:[oldSection indexOfObject:champInfo2] inSection:[champs indexOfObject:section]] toIndexPath:[NSIndexPath indexPathForItem:[section indexOfObject:champInfo2] inSection:[champs indexOfObject:section]]];
[oldSection removeObject:champInfo2];
[oldSection insertObject:champInfo2 atIndex:[section indexOfObject:champInfo2]];
}
}
Upvotes: 1
Views: 65
Reputation: 2660
To perform multiple UICollectionView item updates (insert/delete/move), it is recommended to use performBatchUpdates:completion:
. Otherwise you may encounter invalid indexes.
Link to official Apple's documentation
Upvotes: 0
Reputation: 726579
The upper part of your code (i.e. the sorting) works fine. It can be simplified if you use sort descriptors, but it's definitely not the issue.
The real problem is with the code that moves things around.
Before the first move the indexing of the oldSection1
and self.collectionView
is in sync, i.e. if an item XYZ
is at index i
in oldSection1
, then it is also at index i
in self.collectionView
.
After the first move, however, the indexing gets out of sync, because the move is executed only in self.collectionView
, but not in oldSection1
. For example, if you start with
oldSection1 = C D A B
collectionView = C D A B
and you want it to be
sorted = A B C D
after the first move of C
the data is going to look like
oldSection1 = C D A B
collectionView = A C D B
When it's time to move D
to its new spot, C
gets moved instead.
To fix this issue, make oldSection1
mutable, and execute "parallel" moves as you move things around in self.collectionView
.
Upvotes: 1
Reputation: 8576
It looks like your actual data is correct, but your collection view is displaying them incorrectly since you're iterating over the data, moving one row at a time. This most likely results in re-ordering rows that have already been re-ordered.
Calling [self.collectionView reloadData]
instead of manually moving rows should resolve this issue.
Upvotes: 0