更快的MPMediaItems的NSMutableArray?代码审查

时间:2012-06-18 20:14:51

标签: objective-c ios sorting nsmutablearray

我在iOS编程工作了几周,还有很多需要学习的东西。我有一种包含MPMediaItems的NSMutableArray工作,但它有大约10秒的速度,有1200种物品,我正在寻找一种更快的方法。

我的最终目标是拥有一系列MPMediaItemCollection项目,每个项目代表一张专辑。我不能从MPMediaQuery(据我所知)得到这个,因为我需要从播放列表中获取歌曲。所以我正在对从特定播放列表(“过去4个月”)中获得的歌曲进行排序,然后构建我自己的集合数组。正如我所说,下面的方法有效但速度很慢。即使我只按MPMediaItemPropertyAlbumTitle排序,它仍然需要大约4秒钟(iPhone 4S)。

编辑:我应该提一下,我尝试了排序描述符,但我无法获得工作的关键。 E.g。

NSSortDescriptor *titleDescriptor = [[NSSortDescriptor alloc] initWithKey:@"MPMediaItemPropertyAlbumTitle" ascending:YES];

返回错误

[<MPConcreteMediaItem 0x155e50> valueForUndefinedKey:]: this class is not key value coding-compliant for the key MPMediaItemPropertyAlbumTitle.

守则

MPMediaQuery *query = [MPMediaQuery playlistsQuery];
NSArray *playlists = [query collections];
NSMutableArray *songArray = [[NSMutableArray alloc] init];

for (MPMediaItemCollection *playlist in playlists) {
    NSString *playlistName = [playlist valueForProperty: MPMediaPlaylistPropertyName];
    NSLog (@"%@", playlistName);
    if ([playlistName isEqualToString:@"Last 4 months"]) {

        /* replaced this code with a mutable copy
        NSArray *songs = [playlist items];
        for (MPMediaItem *song in songs) {
            [songArray addObject:song]; 
        }
        */
        // the following replaces the above for-loop
        songArray = [[playlist items] 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]; 
        }];
    }
}

3 个答案:

答案 0 :(得分:3)

我知道这是一个旧线程,但我认为澄清为什么OPs排序代码不起作用很重要,以便任何遇到此代码的人都不会放弃使用NSSortDescriptors。

代码:

[[NSSortDescriptor alloc] initWithKey:@"MPMediaItemPropertyAlbumTitle" ascending:YES];

应该是:

[[NSSortDescriptor alloc] initWithKey:MPMediaItemPropertyAlbumTitle ascending:YES];

因为MPMediaItemPropertyAlbumTitle保存密钥的名称。

我多次使用过此代码。

答案 1 :(得分:2)

根据@cdelacroix的建议,我重新实现了我的比较块以级联三个排序键,只检查低位键,如果更高阶键是相同的。这导致该类型的执行时间减少了50%以上。不过,它并不像我想的那么快,所以如果有人有更好的答案,请发帖。

以下是旧时代与新时代(1221项):

4S executionTime = 10.8,executionTime = 4.7

3GS executionTime = 21.6,executionTime = 9.3

有趣的是,从数组副本的for循环到mutableCopy的转换似乎没有改善。如果有的话,mutableCopy可能慢了十分之一(任何人都对mutableCopy进行了任何基准测试?)。但我保留了改变,因为它看起来更干净。

最后,请注意检查相册标题== nil。请注意,比较认为任何具有零值的内容始终是NSOrderedSame。列表中的一个专辑没有标题集,这使得排序顺序搞砸而没有进行此检查。

MPMediaQuery *query = [MPMediaQuery playlistsQuery];
NSArray *playlists = [query collections];
NSMutableArray *songArray = [[NSMutableArray alloc] init];

for (MPMediaItemCollection *playlist in playlists) {
    NSString *playlistName = [playlist valueForProperty: MPMediaPlaylistPropertyName];
    NSLog (@"%@", playlistName);
    if ([playlistName isEqualToString:@"Last 4 months"]) {

        songArray = [[playlist items] mutableCopy ];

        [songArray sortUsingComparator:^NSComparisonResult(id a, id b) {
            NSComparisonResult compareResult;

            NSString *first1 = [(MPMediaItem*)a valueForProperty:MPMediaItemPropertyAlbumTitle];
            if(first1 == nil) first1 = @" "; // critical because compare will match nil to anything and result in NSOrderedSame
            NSString *second1 = [(MPMediaItem*)b valueForProperty:MPMediaItemPropertyAlbumTitle];
            if(second1 == nil) second1 = @" ";  // critical because compare will match nil to anything and result in NSOrderedSame
            compareResult = [first1 compare:second1];

            if (compareResult == NSOrderedSame) {
                NSString *first2 = [(MPMediaItem*)a valueForProperty:MPMediaItemPropertyAlbumPersistentID];
                NSString *second2 = [(MPMediaItem*)b valueForProperty:MPMediaItemPropertyAlbumPersistentID];
                compareResult = [first2 compare:second2];
                if(compareResult == NSOrderedSame) {
                    NSString *first3 = [(MPMediaItem*)a valueForProperty:MPMediaItemPropertyAlbumTrackNumber];
                    NSString *second3 = [(MPMediaItem*)b valueForProperty:MPMediaItemPropertyAlbumTrackNumber];
                    compareResult = [first3 compare:second3];
                }
            }
            return compareResult;
        }];
    }
}

答案 2 :(得分:0)

您需要了解sort descriptors

然后你的排序就像return [songs sortedArrayUsingDescriptors:sortDescriptors];一样简单,也应该快得多。

编辑:根据OP,MPMediaItem类不符合KVC标准,所以我正在退出答案。