I’m a couple weeks into iOS programming, and have lots to learn. I’ve got a sort of an NSMutableArray containing MPMediaItems working, but it’s about 10 seconds slow with a sort of 1200 items and I’m looking for an approach that would be faster.
My ultimate goal is to have an array of MPMediaItemCollection items, each representing an album. I can’t get this from an MPMediaQuery (as far as I know) because I need to get the songs from a playlist. So I’m sorting the songs I get from a specific playlist (“Last 4 months”) and will then build my own array of collections. As I say, the approach below works but is very slow. Even if I sort only by the MPMediaItemPropertyAlbumTitle, it still takes about 4 seconds (iPhone 4S).
EDIT: I should mention that I tried sort descriptors, but I can’t get the key to work. E.g.
NSSortDescriptor *titleDescriptor = [[NSSortDescriptor alloc] initWithKey:@"MPMediaItemPropertyAlbumTitle" ascending:YES];
This return an error of
[<MPConcreteMediaItem 0x155e50> valueForUndefinedKey:]: this class is not key value coding-compliant for the key MPMediaItemPropertyAlbumTitle.
The Code
MPMediaQuery *query = [MPMediaQuery playlistsQuery];
NSArray *playlists = [query collections];
NSMutableArray *songArray = [[NSMutableArray alloc] init];
for (MPMediaItemCollection *playlist in playlists) {
NSString *playlistName = ;
NSLog (@"%@", playlistName);
if ([playlistName isEqualToString:@"Last 4 months"]) {
/* replaced this code with a mutable copy
NSArray *songs = ;
for (MPMediaItem *song in songs) {
[songArray addObject:song];
}
*/
// the following replaces the above for-loop
songArray = [ mutableCopy ];
[songArray sortUsingComparator:^NSComparisonResult(id a, id b) {
NSString *first1 = [(MPMediaItem*)a valueForProperty:MPMediaItemPropertyAlbumTitle];
NSString *second1 = [(MPMediaItem*)b valueForProperty:MPMediaItemPropertyAlbumTitle];
NSString *first2 = [(MPMediaItem*)a valueForProperty:MPMediaItemPropertyAlbumPersistentID];
NSString *second2 = [(MPMediaItem*)b valueForProperty:MPMediaItemPropertyAlbumPersistentID];
NSString *first3 = [(MPMediaItem*)a valueForProperty:MPMediaItemPropertyAlbumTrackNumber];
NSString *second3 = [(MPMediaItem*)b valueForProperty:MPMediaItemPropertyAlbumTrackNumber];
NSString *first = [NSString stringWithFormat:@"%@%@%03d",first1,first2, [first3 intValue]];
NSString *second = [NSString stringWithFormat:@"%@%@%03d",second1,second2, [second3 intValue]];
return [first compare:second];
}];
}
}
With the suggestion of @cdelacroix I reimplemented my comparison block to cascade the three sort keys, only checking lower order keys if the higher order keys were the same. This resulted in a more than 50% reduction in execution time of the sort. Still, it’s not as fast as I would like, so if anyone has a better answer, please post it.
Here are old times vs. new times (1221 items):
4S executionTime = 10.8, executionTime = 4.7
3GS executionTime = 21.6, executionTime = 9.3
Interestingly, the switch from a for-loop to a mutableCopy for the array copy did not seem to improve things. If anything, mutableCopy was perhaps a 10th of a second slower (anyone done any benchmarking on mutableCopy?). But I left the change in because it is so much cleaner looking.
Lastly, note the check for album title == nil. Be aware that compare thinks anything with a nil value is always NSOrderedSame as anything else. One album in the list didn’t have a title set, and this screwed up the sort order without this check.