DemosJarco
DemosJarco

Reputation: 587

Sorting NSArray of NSDictionary...not completely working

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

Answers (3)

Rufel
Rufel

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

Sergey Kalinichenko
Sergey Kalinichenko

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

rebello95
rebello95

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

Related Questions